Java事务+atomikos[jta]

1.1、事务的定义:

事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功。其必须遵循四个原则(ACID)

1.2、事务四个原则(ACID)

1、原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做;

2、一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是应该处于正确的状态,即数据完整性约束没有被破坏;如银行转帐,A转帐给B,必须保证A的钱一定转给B,一定不会出现A的钱转了但B没收到,否则数据库的数据就处于不一致(不正确)的状态。

3、隔离性(Isolation):并发事务执行之间互不影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性;

4、持久性(Durability):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因比如遇到系统故障或断电造成数据不一致或丢失。

1.3、隔离级别(isolation level)

隔离级别定义了事务与事务之间的隔离程度、隔离级别与并发性是互为矛盾的:隔离程度越高,数据库的并发性越差;隔离程度越低,数据库的并发性越好。

1.4、事务隔离级别并发现象

1、更新丢失(lost update):

    当系统允许两个事务同时更新同一数据时,发生更新丢失。

         A事务读取User表中的id为1的记录(id=1,name=zhansan,age=20)

         B事务读取User表中的id为1的记录(id=1,name=zhansan,age=20)

         A事务将id为1的记录的name修改为lisi,提交事务

         B事务将id为1的记录的age修改22,提交事务

则A事务就会出现更新丢失

 

2、脏读(dirty read)

          当一个事务读取另一个事务尚未提交的修改时,产生脏读。

         A事务读取User表中的id为1的记录(id=1,name=zhansan,age=20)

         A事务将id为1的记录的name修改为lisi(id=1, name=lisi,age=20)

         B事务读取User表中的id为1的记录(id=1, name=lisi,age=20)

         此时A事务撤销更改,事务回滚(id=1,name=zhansan,age=20)

         由于A事务回滚了,数据库内不会有任何操作记录,那么B事务是何时、从哪里读取了错误数据根本无从查起。

 

3、非重复读(nonrepeatableread)

         同一查询在同一事务中多次进行,在此期间,由于其他事务提交了对数据的修改或删除,每次返回不同的结果。

         A事务读取某数据,这个数据已经被B事务读取,并做了修改或删除。所以这数据已经不是以前的数据。

 

4、幻像(phantom read)

          同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,虽然查询条件相同,每次返回的结果集却不同。

     A事务重复持行一个查询,由于其他提交事务所做的插入操作,返回不同的结果集,此时发生幻像读。

 

1.5、隔离级别和对应现象的空值情况

隔离级别

脏读

非重复读

幻读

未提交读

Y

Y

Y

提交读

N

Y

Y

可重复读

N

N

Y

序列化

N

N

N

 

1.6、数据库事务分为本地事务跟全局事务

本地事务:普通事务,独立一个数据库,能保证在该数据库上操作的ACID。

分布式事务:涉及两个或多个数据库源的事务,即跨越多台同类或异类数据库的事务(由每台数据库的本地事务组成的),分布式事务旨在保证这些本地事务的所有操作的ACID,使事务可以跨越多台数据库;

1.7、Java事务类型分为JDBC事务跟JTA事务

JDBC事务:即为上面说的数据库事务中的本地事务,通过connection对象控制管理。

JTA事务:JTA指Java事务API(JavaTransaction API),是Java EE数据库事务规范, JTA只提供了事务管理接口,由应用程序服务器厂商(如WebSphere Application Server)提供实现,JTA事务比JDBC更强大,支持分布式事务。

1.8、Spring事务传播行为:有七大传播行为,也是在TransactionDefinition接口中定义。

PROPAGATION_REQUIRED:支持当前事务,如当前没有事务,则新建一个。

PROPAGATION_SUPPORTS:支持当前事务,如当前没有事务,则已非事务性执行(源码中提示有个注意点,看不太明白,留待后面考究)。

PROPAGATION_MANDATORY:支持当前事务,如当前没有事务,则抛出异常(强制一定要在一个已经存在的事务中执行,业务方法不可独自发起自己的事务)。

PROPAGATION_REQUIRES_NEW:始终新建一个事务,如当前原来有事务,则把原事务挂起。

PROPAGATION_NOT_SUPPORTED:不支持当前事务,始终已非事务性方式执行,如当前事务存在,挂起该事务。

PROPAGATION_NEVER:不支持当前事务;如果当前事务存在,则引发异常。

PROPAGATION_NESTED:如果当前事务存在,则在嵌套事务中执行,如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作(注意:当应用到JDBC时,只适用JDBC 3.0以上驱动)。

1.9、Spring多数据源分布式事务spring+atomikos[jta]+druid+mybatis

spring3.0之后不再支持jtom[jta]了,第三方开源软件atomikos(http://www.atomikos.com/)来实现.

atomikos事务控制框架,其中看到有3种数据源,分别是,SimpleDataSourceBean,AtomikosDataSourceBean,AtomikosNonXADataSourceBean。

  a:SimpleDataSourceBean: 这个是最简单地数据源配置,需要配置XA驱动。

  b:AtomikosDataSourceBean:  分布式数据源,Atomikos实现的数据源,需要配置XA驱动,推荐此配置,可以配置连接池的信息。

  c:AtomikosNonXADataSourceBean: 非分布式数据源,该数据源配置需要普通JDBC的驱动,可以配置连接池:

  Atomikos支持XA(全局事务)和NON-XA(非全局事务),NON-XA[nonxadatasource]效率高于XA.XA事务往往是包括多个数据源的全局事务,非XA是单个数据源的.

   XA连接是一个JTA事务中的参与者。XA连接不支持JDBC的自动提交特性。也就是说应用程序不必在xadatasource[XA]连接上调用Java.sql.Connection.commit()或java.sql.Connection.rollback();而应用程序应该使用UserTransaction.begin(),UserTransaction.commit()和UserTransaction.rollback().


1、  创建两个数据库

1.1、创建第一个数据库multi-db1

CREATE DATABASE `multi-db1` DEFAULT CHARACTER SET utf8;
USE `multi-db1`;
DROP TABLE IF EXISTS `t_user`;

CREATE TABLE `t_user` (
  `id` varchar(100) DEFAULT NULL,
  `name` varchar(200) DEFAULT NULL,
  `gender` varchar(2) DEFAULT NULL,
  `birthday` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1.2、创建第二个数据库multi-db2

CREATE DATABASE `multi-db2` DEFAULT CHARACTER SET utf8;
USE `multi-db2`;
DROP TABLE IF EXISTS `t_user`;

CREATE TABLE `t_user` (
  `id` varchar(100) DEFAULT NULL,
  `name` varchar(200) DEFAULT NULL,
  `gender` varchar(2) DEFAULT NULL,
  `birthday` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2、  创建一个maven的项目类型为jar项目目录为


3、项目的POM文件pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.jyd.transaction</groupId>
	<artifactId>DTransaction</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.2.5.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>4.2.5.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.0.26</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.36</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.12</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.10</version>
		</dependency>

		<!-- transaction -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>4.2.5.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>jta</artifactId>
			<version>1.1</version>
		</dependency>
		<dependency>
			<groupId>com.atomikos</groupId>
			<artifactId>atomikos-util</artifactId>
			<version>4.0.2</version>
		</dependency>
		<dependency>
			<groupId>com.atomikos</groupId>
			<artifactId>transactions</artifactId>
			<version>4.0.2</version>
		</dependency>
		<dependency>
			<groupId>com.atomikos</groupId>
			<artifactId>transactions-jta</artifactId>
			<version>4.0.2</version>
		</dependency>
		<dependency>
			<groupId>com.atomikos</groupId>
			<artifactId>transactions-jdbc</artifactId>
			<version>4.0.2</version>
		</dependency>
		<dependency>
			<groupId>com.atomikos</groupId>
			<artifactId>transactions-api</artifactId>
			<version>4.0.2</version>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib-nodep</artifactId>
			<version>3.2.2</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.8.0</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.0</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.3.0</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.4.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>4.2.5.RELEASE</version>
		</dependency>

	</dependencies>
	<build>
		<plugins>
			<!-- 资源文件拷贝插件 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-resources-plugin</artifactId>
				<version>2.7</version>
				<configuration>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>
4、配置数据源参数db.properties
#mysql-Used to verify the effectiveness of the database connection 
validationQuery=SELECT 1
jdbc.initialSize=5
jdbc.maxActive=20
jdbc.maxWait=60000
jdbc.poolPreparedStatements=false
jdbc.poolMaximumIdleConnections=0
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.xaDataSourceClassName=com.alibaba.druid.pool.xa.DruidXADataSource
#jdbc.xaDataSourceClassName=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
#1.tms business.  2.The db level optimization,data concurrency,desirable.
master.jdbc.url=jdbc:mysql://localhost:3306/multi-db1?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
slave.jdbc.url=jdbc:mysql://localhost:3306/multi-db2?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc.username=root
jdbc.password=123456
5、AtomikosDataSourceBean[XA(全局事务)]数据源配置datasource-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc 
	http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
	http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/tx 
	http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd" default-lazy-init="true">
	<description>配置DB1-DB2数据源信息</description>
	<!-- com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean -->
 	<bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close" abstract="true">  
       <property name="xaDataSourceClassName" value="${jdbc.xaDataSourceClassName}"/>  <!-- SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana]  -->
       <property name="poolSize" value="10" />  
       <property name="minPoolSize" value="10"/>  
       <property name="maxPoolSize" value="30"/>  
       <property name="borrowConnectionTimeout" value="60"/>  
       <property name="reapTimeout" value="20"/>  
       <property name="maxIdleTime" value="60"/>  
       <property name="maintenanceInterval" value="60"/>  
       <property name="loginTimeout" value="60"/>  
       <property name="testQuery" value="${validationQuery}"/>  
   	</bean>  
 	<bean id="db1DataSource" parent="abstractXADataSource">  
 		<property name="uniqueResourceName" value="DB1" />  
	    <property name="xaProperties">
            <props>
           		<prop key="driverClassName">${jdbc.driverClassName}</prop>
                <prop key="url">${master.jdbc.url}</prop>
                <prop key="password">${jdbc.password}</prop>
                 <!--  <prop key="user">${jdbc.username}</prop> --> <!-- mysql -->
                <prop key="username">${jdbc.username}</prop>   <!-- durid -->
             	<prop key="initialSize">0</prop>
				<prop key="maxActive">20</prop> <!-- 若不配置则代码执行"{dataSource-1} inited"此处停止  -->
				<prop key="minIdle">0</prop>
				<prop key="maxWait">60000</prop>
           		<prop key="validationQuery">${validationQuery}</prop>
				<prop key="testOnBorrow">false</prop>
				<prop key="testOnReturn">false</prop>
				<prop key="testWhileIdle">true</prop>
				<prop key="removeAbandoned">true</prop>
				<prop key="removeAbandonedTimeout">1800</prop>
				<prop key="logAbandoned">true</prop>
				<prop key="filters">mergeStat</prop>
            </props>
        </property>
    </bean>  
   	<bean id="db2DataSource" parent="abstractXADataSource">  
   		<property name="uniqueResourceName" value="DB2" />  
	    <property name="xaProperties">
            <props>
          		<prop key="driverClassName">${jdbc.driverClassName}</prop>
                <prop key="url">${slave.jdbc.url}</prop>
                <prop key="password">${jdbc.password}</prop>
                <!--  <prop key="user">${jdbc.username}</prop> -->
                <prop key="username">${jdbc.username}</prop>
               	<prop key="initialSize">0</prop>
				<prop key="maxActive">20</prop>
				<prop key="minIdle">0</prop>
				<prop key="maxWait">60000</prop>
                <prop key="validationQuery">${validationQuery}</prop>
				<prop key="testOnBorrow">false</prop>
				<prop key="testOnReturn">false</prop>
				<prop key="testWhileIdle">true</prop>
				<prop key="removeAbandoned">true</prop>
				<prop key="removeAbandonedTimeout">1800</prop>
				<prop key="logAbandoned">true</prop>
				<prop key="filters">mergeStat</prop>
            </props>
        </property>
    </bean>  
</beans>
6、配置mybatis-config

         mybatis-config-db1.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <typeAlias alias="User"  type="com.jyd.entity.User"/>
    </typeAliases>
    <mappers>
        <mapper resource="com/jyd/xml/UserMapper.xml" />
    </mappers>
</configuration>

mybatis-config-db2.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <typeAlias alias="UserInfo"  type="com.jyd.entity.UserInfo"/>
    </typeAliases>
    <mappers>
        <mapper resource="com/jyd/xml/UserInfoMapper.xml" />
    </mappers>
</configuration>
7、mybatis的配置mybatis-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xsi:schemaLocation="http://www.springframework.org/schema/mvc 
	http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
	http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/tx 
	http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd" default-lazy-init="true">
	<bean id="db1SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis/mybatis-config-db1.xml" />
        <property name="dataSource" ref="db1DataSource" />
    </bean>
 
    <bean id="db2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis/mybatis-config-db2.xml" />
        <property name="dataSource" ref="db2DataSource" />
    </bean>
</beans>
8、Mapper的管理及注入,为mybatis的dao层mapper接口注入[绑定]sqlSessionFactory
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xsi:schemaLocation="http://www.springframework.org/schema/mvc 
	http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
	http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/tx 
	http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd" default-lazy-init="true">
	<description>MyBatis为不同的mapper注入sqlSessionFactory</description>
    <!-- Mapper的管理及注入 -->
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="sqlSessionFactory" ref="db1SqlSessionFactory" />
        <property name="mapperInterface" value="com.jyd.dao.UserMapper" />
    </bean>
     
    <bean id="userInfoMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="sqlSessionFactory" ref="db2SqlSessionFactory" />
        <property name="mapperInterface" value="com.jyd.dao.UserInfoMapper" />
    </bean>
</beans>
9、atomikos事务配置transaction-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc 
	http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
	http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/tx 
	http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd" default-lazy-init="true">
	<description>配置事物</description>
	<!-- atomikos事务管理器 -->
	<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
        <property name="forceShutdown">
            <value>true</value>
        </property>
    </bean>
 
    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
        <property name="transactionTimeout" value="300" />
    </bean>
 	<!-- spring 事务管理器 -->  
    <bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager" ref="atomikosTransactionManager" />
        <property name="userTransaction" ref="atomikosUserTransaction" />
        <!-- 必须设置,否则程序出现异常 JtaTransactionManager does not support custom isolation levels by default -->
        <property name="allowCustomIsolationLevels" value="true"/> 
    </bean>

    <aop:config  proxy-target-class="true">
        <aop:advisor pointcut="(execution(* com.jyd.service.*.* (..)))" advice-ref="txAdvice" />
    </aop:config>
 
    <tx:advice id="txAdvice" transaction-manager="springTransactionManager">
        <tx:attributes>
            <tx:method name="get*"  propagation="REQUIRED"  read-only="true" />
            <tx:method name="find*"  propagation="REQUIRED"  read-only="true" />
            <tx:method name="has*"  propagation="REQUIRED"  read-only="true" />
            <tx:method name="locate*"  propagation="REQUIRED"  read-only="true" />
            <tx:method name="register*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
        </tx:attributes>
    </tx:advice>
</beans>
10、配置jta启动参数在jta.properties,最后追加详细
com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
com.atomikos.icatch.console_file_name = /home/logs/tx/tx.out.log
com.atomikos.icatch.log_base_name = txlog
com.atomikos.icatch.tm_unique_name = com.atomikos.spring.jdbc.tm
com.atomikos.icatch.console_log_level=DEBUG
11、spring主配置文件spring-context.xml

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:mvc="http://www.springframework.org/schema/mvc"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
                        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd    
                        http://www.springframework.org/schema/context    
                        http://www.springframework.org/schema/context/spring-context-3.2.xsd
                        http://www.springframework.org/schema/aop 
            			http://www.springframework.org/schema/aop/spring-aop-3.2.xsd    
                        http://www.springframework.org/schema/mvc    
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">  
                        
	<!-- 使用annotation 自动注册bean,并检查@Required,@Autowired的属性已被注入 -->
	<context:component-scan base-package="com.jyd" />
	
 	<!-- 使用AspectJ方式配置AOP -->  
	<aop:aspectj-autoproxy />
	
	<!-- 引入属性配置文件 -->
 	<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
		<property name="location" value="classpath:properties/db.properties" />        
	</bean>  
	
	<!--或 <context:property-placeholder location="classpath*:*.properties" /> -->
	<import resource="datasource-context.xml"/>
	<import resource="mapper-context.xml"/>
	<import resource="mybatis-context.xml"/>
	<import resource="transaction-context.xml"/>
</beans>

12、创建实体bean类(User.java|UserInfo.java)

User.java

package com.jyd.entity;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {

	private static final long serialVersionUID = -5650864083291329775L;
	private String id;
	private String name;
	private String gender;
	private Date birthday;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
}

UserInfo.java

package com.jyd.entity;

import java.io.Serializable;
import java.util.Date;

public class UserInfo implements Serializable {

	private static final long serialVersionUID = 7402046259459506152L;
	private String id;
	private String name;
	private String gender;
	private Date birthday;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
}
13、创建mybatis的mapper和dao接口(UserMapper.java|UserInfoMapper.java)和对应mapper文件

UserMapper.java

package com.jyd.dao;

import org.springframework.stereotype.Repository;

import com.jyd.entity.User;

@Repository
public interface UserMapper {
	int insert(User record);
}

UserInfoMapper.java

package com.jyd.dao;

import org.springframework.stereotype.Repository;

import com.jyd.entity.UserInfo;

@Repository
public interface UserInfoMapper {
	int insert(UserInfo record);  
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.jyd.dao.UserMapper" >

  <insert id="insert" parameterType="com.jyd.entity.User" >
    insert into t_user (id, name, gender, birthday)
    values (#{id}, #{name}, #{gender},#{birthday})
  </insert>
</mapper>

UserInfoMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.jyd.dao.UserInfoMapper" >

  <insert id="insert" parameterType="com.jyd.entity.UserInfo" >
    insert into t_user (id, name, gender, birthday)
    values (#{id}, #{name}, #{gender},#{birthday})
  </insert>
</mapper>
14、创建UserService服务层和实现(UserService.java|UserServiceImpl.java)

UserService.java

package com.jyd.service;

import com.jyd.entity.User;
import com.jyd.entity.UserInfo;

public interface UserService {
	boolean registerUser(User user, UserInfo userInfo);  
}

UserServiceImpl.java

package com.jyd.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jyd.dao.UserInfoMapper;
import com.jyd.dao.UserMapper;
import com.jyd.entity.User;
import com.jyd.entity.UserInfo;
import com.jyd.service.UserService;

@Service("userService")  
public class UserServiceImpl implements UserService {

	//log  
    private static final Logger LOG = LoggerFactory.getLogger(UserServiceImpl.class);  
      
    @Autowired  
    private UserMapper userMapper;  
    @Autowired  
    private UserInfoMapper userInfoMapper;  
	@Override
	public boolean registerUser(User user, UserInfo userInfo) {

		boolean resRegister = false;  
        try {  
            if(userMapper.insert(user) != 1){  
                throw new RuntimeException("注册用户:User表数据插入不一致.");  
            }  
            if(userInfoMapper.insert(userInfo) != 1){  
                throw new RuntimeException("注册用户:UserInfo表数据插入不一致.");  
            }  
            resRegister = true;  
        } catch (Exception e) {  
            LOG.info("注册用户:数据库保存异常." + e.getMessage(), e);  
            throw new RuntimeException("注册用户:数据库保存异常");  
        }  
        return resRegister; 
	}
}
15、Junit测试代码
package com.jyd.test;

import java.util.Calendar;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.jyd.entity.User;
import com.jyd.entity.UserInfo;
import com.jyd.service.UserService;


@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {"classpath:spring-context.xml"}) 
public class JTATest extends AbstractJUnit4SpringContextTests{

	//log  
    private static final Logger LOG = LoggerFactory.getLogger(JTATest.class);  
      
    @Autowired
    private UserService userService;  
      
    @Test  
    public void testRegister(){  
       
    	User user = new User();
    	user.setId("1");
    	user.setName("张三");
    	user.setGender("男");
    	user.setBirthday(Calendar.getInstance().getTime());
    	
    	UserInfo userInfo = new UserInfo();
    	userInfo.setId("1");
    	userInfo.setName("张三");
    	userInfo.setGender("男");
    	userInfo.setBirthday(Calendar.getInstance().getTime());
    	
        if(userService.registerUser(user, userInfo)){  
            LOG.info("##用户注册成功");  
        }else{  
            LOG.info("##用户注册失败");  
        }  
    } 
}

可以做异常测试,其中如何方法出错了,都会回滚事务

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值