数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
一个数据库事务通常包含了一个序列的对数据库的读/写操作。它的存在包含有以下两个目的:
为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
当事务被提交给了DBMS(数据库管理系统),则DBMS(数据库管理系统)需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要被回滚,回到事务执行前的状态;同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。
特性
并非任意的对数据库的操作序列都是数据库事务。数据库事务拥有以下四个特性,习惯上被称之为ACID特性。
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。
Spring下由三种途径对事物进行管理:编程式事务管理、声明式事务管理和AOP事务管理。其中AOP事务管理又分AOP注解事务管理和AOP XML配置两种
AOP注解事务管理
spring.xml
(spring的配置文件,不一定叫spring.xml)文件中的配置:
1.配置数据源(我使用的是tddl,改为自己的数据源)
<!-- datasource begin -->
<bean id="tddlGroupDataSource" class="com.taobao.tddl.jdbc.group.TGroupDataSource"
init-method="init">
<property name="appName" value="${alibaba.intl.apaas.db.app.name}"/>
<property name="dbGroupKey" value="${alibaba.intl.apaas.db.group.key}"/>
</bean>
<!-- datasource end -->
2. 配置sping的事务管理
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sca="http://www.springframework.org/schema/sca"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- Transaction begin -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="tddlGroupDataSource" />
</bean>
<!-- transaction end -->
</beans>
<tx:annotation-driven transaction-manager="transactionManager" />
这句话加上的话,在spring获取bean的时候,要使用接口!
3.配置SqlMapClient(我的持久层使用了ibatis,所以需要配置这个)
<bean id="apaasSqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="biz/sql-map-config.xml"/>
<property name="dataSource" ref="tddlGroupDataSource"/>
</bean>
sql-map-config.xml的配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings cacheModelsEnabled="true" enhancementEnabled="true"
errorTracingEnabled="true" lazyLoadingEnabled="true" maxRequests="32"
maxSessions="10" maxTransactions="5" useStatementNamespaces="true" />
<sqlMap resource="sqlmap/sqlmap-apaas-label.xml" />
<!-- <sqlMap resource="sqlmap/sqlmap-apaas-label-sorce.xml" /> -->
</sqlMapConfig>
sqlmap-apaas-label-sorce.xml配置就不写了,就是ibatis的jdbc操作。
4.配置dao和service
<bean id="appLabelDao" class="com.alibaba.intl.apaas.common.monitor.dao.impl.AppLabelDaoImpl"
parent="baseSqlMapClientDAO"/>
<bean id="appLabelServiceBean" class="com.alibaba.intl.apaas.common.monitor.service.impl.AppLabelServiceImpl">
<property name="appLabelDao">
<ref bean="appLabelDao"/>
</property>
</bean>
AppLabelServiceImpl
的Java类的配置:
public class AppLabelServiceImpl implements AppLabelService {
private AppLabelDao appLabelDao;
@Transactional
public Integer insertAppLabel() {
appLabelDao.jdbcOperate1();
appLabelDao.jdbcOperate2();
appLabelDao.jdbcOperate3();
appLabelDao.jdbcOperate4();
}
}
这里使用@Transactional
这个注解,这个注解的原理和具体使用方式我会在别的文章里面介绍。 在方法insertAppLabel
上添加@Transactional
这个注解,声明该方法要在一个事务中进行处理。 这个方法一共有四个jdbc操作jdbcOperate1
、jdbcOperate2
、jdbcOperate3
、jdbcOperate4
,如果在整个insertAppLabel
方法的任何地方抛出runtimeException,就会执行rollback。即所有操作将被回滚。
测试类:
public class AppLabelServiceImplTest {
private static AppLabelService service;
@BeforeClass
public static void beforeClass() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:biz/sca-appinfo-provider-context.xml");
service = (AppLabelService)context.getBean("appLabelServiceBean");
}
@Test
public void testInsert(){
service.insertAppLabel( );
}
}
PS:service = (AppLabelService)context.getBean("appLabelServiceBean");
此处应该注意,一定要用AppLabelService
这个接口,二不能用AppLabelServiceImpl
这个实现类。 因为Spring文档中有写:Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理,如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。
如果不使用AppLabelService而使用AppLabelServiceImpl的话,在执行程序的时候就会报错:classCastException
这里,service也不能是new出来的,必须要用spring进行管理。
好