一. Mango事务
mango支持编程式事务和使用TransactionTemplate进行事务;
编程式事务:
Transaction tx = TransactionFactory.newTransaction(); try { //业务处理,比如下面的转账操作 dao.transferMoney(zhangsan, -money); dao.transferMoney(lisi, money); } catch (Throwable e) { tx.rollback(); //事务回滚 return; } tx.commit(); //事务提交
实例代码:
package com.lhf.mango.transaction; import com.lhf.mango.dao.AccountDao; import com.lhf.mango.entity.Account; import org.jfaster.mango.datasource.DriverManagerDataSource; import org.jfaster.mango.operator.Mango; import org.jfaster.mango.transaction.Transaction; import org.jfaster.mango.transaction.TransactionFactory; import org.jfaster.mango.util.logging.MangoLogger; import javax.sql.DataSource; /** * @ClassName: AccountMain1 * @Desc: 编程式事务 * @Author: liuhefei * @Date: 2018/12/24 9:28 */ public class AccountMain1 { public static void main(String[] args){ MangoLogger.useLog4J2Logger(); // 使用log4j2输出日志,log4j2.xml文件在resources目录下 //定义数据源 String driverClassName = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/mango_example?useSSL=false"; String username = "root"; String passowrd = "root"; DataSource ds = new DriverManagerDataSource(driverClassName,url, username, passowrd); Mango mango = Mango.newInstance(ds); //使用数据源初始化mango AccountDao accountDao = mango.create(AccountDao.class); Account account1 = new Account(); Account account2 = new Account(); account1.setUid(3); account1.setName("小花"); account1.setMoney(1500); accountDao.addAccount(account1); account2.setUid(4); account2.setName("小美"); account2.setMoney(1500); accountDao.addAccount(account2); //转账前 System.out.println("转账前:"); System.out.println(accountDao.getAccount(1).toString()); System.out.println(accountDao.getAccount(2).toString()); //开启事务 Transaction tx = TransactionFactory.newTransaction(); int money = 1500; try{ accountDao.transferMoney(1, -money); accountDao.transferMoney(2, money); }catch (Throwable e){ tx.rollback(); //回滚 return; } tx.commit(); //提交事务 //转账后 System.out.println("转账后:"); System.out.println(accountDao.getAccount(1).toString()); System.out.println(accountDao.getAccount(2).toString()); } }
使用TransactionTemplate:
TransactionTemplate.execute(new TransactionAction() { @Override public void doInTransaction(TransactionStatus status) { //业务处理,比如下面的转账操作 dao.transferMoney(zhangsan, -money); dao.transferMoney(lisi, money); } });
实例代码:
package com.lhf.mango.transaction; import com.lhf.mango.dao.AccountDao; import org.jfaster.mango.datasource.DriverManagerDataSource; import org.jfaster.mango.operator.Mango; import org.jfaster.mango.transaction.TransactionAction; import org.jfaster.mango.transaction.TransactionStatus; import org.jfaster.mango.transaction.TransactionTemplate; import org.jfaster.mango.util.logging.MangoLogger; import javax.sql.DataSource; /** * @ClassName: AccountMain2 * @Desc: 使用Mango的TransactionTemplate 进行事务控制 * @Author: liuhefei * @Date: 2018/12/24 9:28 */ public class AccountMain2 { public static void main(String[] args){ MangoLogger.useLog4J2Logger(); // 使用log4j2输出日志,log4j2.xml文件在resources目录下 //定义数据源 String driverClassName = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/mango_example?useSSL=false"; String username = "root"; String passowrd = "root"; DataSource ds = new DriverManagerDataSource(driverClassName,url, username, passowrd); Mango mango = Mango.newInstance(ds); //使用数据源初始化mango final AccountDao accountDao = mango.create(AccountDao.class); //转账前 System.out.println("转账前:"); System.out.println(accountDao.getAccount(3).toString()); System.out.println(accountDao.getAccount(4).toString()); final int money = 1000; if(accountDao.getAccount(3).getMoney() > money){ TransactionTemplate.execute(new TransactionAction() { public void doInTransaction(TransactionStatus transactionStatus) { accountDao.transferMoney(3, -money); //减去 accountDao.transferMoney(4, money); //加上 } }); }else{ System.out.println("余额不足,转账失败"); } //转账后 System.out.println("转账后:"); System.out.println(accountDao.getAccount(3).toString()); System.out.println(accountDao.getAccount(4).toString()); } }
二. Mango日志
mango框架拥有强大的日志处理功能,能通过下面任意一个“日志工具”输出日志(能查看执行的SQL与参数):
Slf4J
Log4J2
Log4J
Console(控制台,也就是通过System.out输出)
(1)使用Slf4J输出日志:
准备配置文件
logback.xml 配置文件如下,需要注意的是logger的name为org.jfaster.mango,level为debug。
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} - %msg%n</pattern> </encoder> </appender> <logger name="org.jfaster.mango" level="debug" additivity="false"> <appender-ref ref="STDOUT"/> </logger> <root level="error"> <appender-ref ref="STDOUT" /> </root> </configuration>
Main方法运行程序:
有了前面的配置文件,当我们直接使用Main方法运行程序时,只需将下面的代码放到Main方法的最前面,即可让mango框架使用Slf4J输出日志信息。
MangoLogger.useSlf4JLogger();
上面的代码中MangoLogger的类全名为org.jfaster.mango.util.logging.MangoLogger
WEB容器运行程序:
很多时候我们并不直接通过Main方法运行自己的程序,而是使用tomcat,jetty等WEB容器。这时我们只需将下面的“监听器”拷配到web.xml文件的最前面,即可让mango框架使用Slf4J输出日志信息。
<listener> <listener-class>org.jfaster.mango.plugin.listener.Slf4JLoggerListener</listener-class> </listener>
(2)使用Log4J2输出日志:
准备配置文件
log4j2.xml 配置文件如下,需要注意的是Logger的name为org.jfaster.mango,level为debug。
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </Appenders> <Loggers> <Logger name="org.jfaster.mango" level="debug" additivity="false"> <AppenderRef ref="Console"/> </Logger> <Root level="error"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
Main方法运行程序:
有了前面的配置文件,当我们直接使用Main方法运行程序时,只需将下面的代码放到Main方法的最前面,即可让mango框架使用Log4J2输出日志信息。
MangoLogger.useLog4J2Logger();
上面的代码中MangoLogger的类全名为org.jfaster.mango.util.logging.MangoLogger
WEB容器运行程序:
很多时候我们并不直接通过Main方法运行自己的程序,而是使用tomcat,jetty等WEB容器。这时我们只需将下面的“监听器”拷配到web.xml文件的最前面,即可让mango框架使用Log4J2输出日志信息。
<listener> <listener-class>org.jfaster.mango.plugin.listener.Log4J2LoggerListener</listener-class> </listener>
(3)使用Log4J输出日志:
准备配置文件
log4j.xml 配置文件如下,需要注意的是logger的name为org.jfaster.mango,level为debug。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration> <appender name="console" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="[%d{dd HH:mm:ss,SSS\} %-5p] [%t] %c{2\} - %m%n" /> </layout> </appender> <logger name="org.jfaster.mango" additivity="false"> <level value="debug" /> <appender-ref ref="console" /> </logger> <root> <level value="info" /> <appender-ref ref="console"/> </root> </log4j:configuration>
Main方法运行程序:
有了前面的配置文件,当我们直接使用Main方法运行程序时,只需将下面的代码放到Main方法的最前面,即可让mango框架使用Log4J输出日志信息。
MangoLogger.useLog4JLogger();
上面的代码中MangoLogger的类全名为org.jfaster.mango.util.logging.MangoLogger
WEB容器运行程序:
很多时候我们并不直接通过Main方法运行自己的程序,而是使用tomcat,jetty等WEB容器。这时我们只需将下面的“监听器”拷配到web.xml文件的最前面,即可让mango框架使用Log4J输出日志信息。
<listener> <listener-class>org.jfaster.mango.plugin.listener.Log4JLoggerListener</listener-class> </listener>
(4)使用控制台输出日志:
使用System.out输出日志到控制台不需要配置文件。
Main方法运行程序:
只需要在Main方法的最前面加入如下代码,即可让Mango框架使用控制台输出日志信息:
MangoLogger.useConsoleLogger();
上面的代码中MangoLogger的类全名为org.jfaster.mango.util.logging.MangoLogger
WEB容器运行程序:
很多时候我们并不直接通过Main方法运行自己的程序,而是使用tomcat,jetty等WEB容器。这时我们只需将下面的“监听器”拷配到web.xml文件的最前面,即可让mango框架使用控制台输出日志信息。
<listener> <listener-class>org.jfaster.mango.plugin.listener.ConsoleLoggerListener</listener-class> </listener>
三. Mango集成Spring
在项目开发中,一般都会使用spring管理对象,进行依赖注入。 我们能通过mango自带的spring插件,便捷的将mango集成到spring中。
纯配置文件集成:
纯配置文件集成是最简单的集成方式,所有的集成操作均在spring配置文件中,由spring容器创建数据库源工厂,mango对象和扫描使用@DB注解修饰的DAO类。
Mango框架使用SimpleDataSourceFactory连接单一数据库,
使用MasterSlaveDataSourceFactory连接主从数据库,
使用MultipleDatabaseDataSourceFactory连接混合数据库集群,
下面将分别给出这3种方式连数据库的配置实例。
(1)连单一数据库配置实例:
<beans> <!-- 配置数据源工厂 --> <bean id="dsf" class="org.jfaster.mango.datasource.SimpleDataSourceFactory"> <property name="dataSource"> <bean class="org.jfaster.mango.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mango_example" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> </property> </bean> <!-- 配置mango对象 --> <bean id="mango" class="org.jfaster.mango.operator.Mango" factory-method="newInstance"> <property name="dataSourceFactory" ref="dsf" /> </bean> <!-- 配置扫描使用@DB注解修饰的DAO类 --> <bean class="org.jfaster.mango.plugin.spring.MangoDaoScanner"> <property name="packages"> <list> <!-- 扫描包名 --> <value>org.jfaster.mango.example.spring</value> <!-- <value>其他需要扫描的包</value> --> </list> </property> </bean> </beans>
上面的配置主要包含3部分。
配置数据源工厂。DriverManagerDataSource数据源是mango框架对DataSource的简单实现,仅供测试使用,如果是生产环境,请使用HikariCP,c3p0,dbcp等高性能数据源。
配置mango对象。创建mango对象的最佳途径是通过Mango类的静态方法newInstance,所以使用了factory-method指定静态方法。
配置扫描使用@DB注解修饰的DAO类。MangoDaoScanner类是一个扫描DAO的扫描器,它能自动扫描packages属性中指定包下的所有类,识别出@DB注解修饰的DAO类,并将他自动加载到spring大工厂中,这样我们既能从ApplicationContext中直接getBean获得dao实例,也能将dao实例直接Autowired到所有由spring管理的类上。需要注意的是所有DAO类必须以DAO或Dao结尾,才能被扫描器识别。
(2)连主从数据库配置实例:
<beans> <!-- 配置主从数据源工厂 --> <bean id="dsf" class="org.jfaster.mango.datasource.MasterSlaveDataSourceFactory"> <property name="master"> <bean class="org.jfaster.mango.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mango_example_master" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> </property> <property name="slaves"> <list> <bean class="org.jfaster.mango.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mango_example_slave1" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> <bean class="org.jfaster.mango.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mango_example_slave2" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> </list> </property> </bean> <!-- 配置mango对象 --> <bean id="mango" class="org.jfaster.mango.operator.Mango" factory-method="newInstance"> <property name="dataSourceFactory" ref="dsf" /> </bean> <!-- 配置扫描使用@DB注解修饰的DAO类 --> <bean class="org.jfaster.mango.plugin.spring.MangoDaoScanner"> <property name="packages"> <list> <!-- 扫描包名 --> <value>org.jfaster.mango.example.spring</value> <!-- <value>其他需要扫描的包</value> --> </list> </property> </bean> </beans>
(3)连多个数据库集群配置实例:
<beans> <!-- 配置简单数据源工厂 --> <bean id="simpleDataSourceFactory" class="org.jfaster.mango.datasource.SimpleDataSourceFactory"> <property name="name" value="dsf1" /> <property name="dataSource"> <bean class="org.jfaster.mango.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mango_example" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> </property> </bean> <!-- 配置主从数据源工厂 --> <bean id="masterSlaveDataSourceFactory" class="org.jfaster.mango.datasource.MasterSlaveDataSourceFactory"> <property name="name" value="dsf2" /> <property name="master"> <bean class="org.jfaster.mango.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mango_example_master" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> </property> <property name="slaves"> <list> <bean class="org.jfaster.mango.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mango_example_slave1" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> <bean class="org.jfaster.mango.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mango_example_slave2" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> </list> </property> </bean> <!-- 配置mango对象 --> <bean id="mango" class="org.jfaster.mango.operator.Mango" factory-method="newInstance"> <property name="dataSourceFactories"> <list> <ref bean="simpleDataSourceFactory" /> <ref bean="masterSlaveDataSourceFactory" /> </list> </property> </bean> <!-- 配置扫描使用@DB注解修饰的DAO类 --> <bean class="org.jfaster.mango.plugin.spring.MangoDaoScanner"> <property name="packages"> <list> <!-- 扫描包名 --> <value>org.jfaster.mango.example.spring</value> <!-- <value>其他需要扫描的包</value> --> </list> </property> </bean> </beans>
配置文件加代码集成:
一般情况下使用纯配置文件集成就能完成大多数项目需求,但在有些项目中,我们需要自己管理数据源工厂,以便在线上动态切换数据源。这时数据源工厂和mango对象对象就不能简单的交由spring管理,我们需要使用配置文件加代码的方式来完成集成。
至此,关于Mango的系列分享就完了,由于工作的原因,没能及时分享出来,望见谅,同时感谢诸君的支持!
代码见github: https://github.com/JavaCodeMood/mango-example1