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