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}"</span>/></span> <span class="hljs-comment"><!-- SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana] --></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="20"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"poolSize"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"10"</span> /></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="21"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"minPoolSize"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"10"</span>/></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="22"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"maxPoolSize"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"30"</span>/></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="23"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"borrowConnectionTimeout"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"60"</span>/></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="24"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"reapTimeout"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"20"</span>/></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="25"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"maxIdleTime"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"60"</span>/></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="26"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"maintenanceInterval"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"60"</span>/></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="27"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"loginTimeout"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"60"</span>/></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="28"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"testQuery"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${validationQuery}"/>
- </bean>
- <bean id="db1DataSource" parent="abstractXADataSource">
- <property name="uniqueResourceName" value="DB1" />
- <property name="xaProperties">
- <props>
- <prop key="driverClassName">${jdbc.driverClassName}<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="35"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"url"</span>></span>${master.jdbc.url}</prop>
- <prop key="password">${jdbc.password}<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="37"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-comment"><!-- <prop key="user">${jdbc.username}</prop> --> <!-- mysql -->
- <prop key="username">${jdbc.username}<span class="hljs-tag"></<span class="hljs-name">prop</span>></span> <span class="hljs-comment"><!-- durid --></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="39"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"initialSize"</span>></span>0<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="40"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"maxActive"</span>></span>20<span class="hljs-tag"></<span class="hljs-name">prop</span>></span> <span class="hljs-comment"><!-- 若不配置则代码执行"{dataSource-1} inited"此处停止 --></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="41"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"minIdle"</span>></span>0<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="42"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"maxWait"</span>></span>60000<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="43"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"validationQuery"</span>></span>${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}<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="59"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"url"</span>></span>${slave.jdbc.url}</prop>
- <prop key="password">${jdbc.password}<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="61"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-comment"><!-- <prop key="user">${jdbc.username}</prop> -->
- <prop key="username">${jdbc.username}<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="63"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"initialSize"</span>></span>0<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="64"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"maxActive"</span>></span>20<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="65"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"minIdle"</span>></span>0<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="66"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"maxWait"</span>></span>60000<span class="hljs-tag"></<span class="hljs-name">prop</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="67"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"validationQuery"</span>></span>${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("##用户注册失败");
- }
- }
- }
可以做异常测试,其中如何方法出错了,都会回滚事务
</div>