手记

进阶—极速分布式ORM框架---Mango(三)

一. 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


1人推荐
随时随地看视频
慕课网APP