第五天
1 Spring与jdbc结合
jdbc编程不变,主要是Connection对象的维护,即配置并使用数据源
1) <!-- 基于jdk的规范数据源 -->
<bean name="dataSource1"
class="oracle.jdbc.pool.OracleConnectionPoolDataSource">
<property name="networkProtocol">
<value>tcp</value>
</property>
<property name="databaseName">
<value>XE</value>
</property>
<property name="driverType">
<value>thin</value>
</property>
<property name="portNumber">
<value>1521</value>
</property>
<property name="user">
<value>briup</value>
</property>
<property name="serverName">
<value>127.0.0.1</value>
</property>
<property name="password">
<value>briup</value>
</property>
</bean>
注意:别忘了读取配置文件
<!-- 读取这个资源文件 读完之后下面就可以用${key}来去文件中的value值了 -->
<!-- 这种方式是我们第一节学习的那种配置方式方式的简写 -->
<context:property-placeholder location="com/briup/db/jdbc/jdbc.properties"/>
2) <!-- dbcp数据源 -->
<bean id="dataSource2"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>${jdbc.driverClassName}</value>
</property>
<property name="url">
<value>${jdbc.url}</value>
</property>
<property name="username">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<!-- 最大连接数 -->
<property name="maxActive">
<value>80</value>
</property>
<!-- 最大空闲连接数 -->
<property name="maxIdle">
<value>20</value>
</property>
<!-- 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间 单位:毫秒 -->
<!-- 超过时间则抛出异常,如果设置为-1表示无限等待 -->
<property name="maxWait">
<value>3000</value>
</property>
</bean>
3) <!-- spring提供的一种数据源 -->
<bean id="dataSource3"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${jdbc.driverClassName}</value>
</property>
<property name="url">
<value>${jdbc.url}</value>
</property>
<property name="username">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
spring在jdbc的使用中还给我们提供了一个模板类:JdbcTemplate
用以简化我们的jdbc操作
例如:
//使用xml进行配置时候的java类中的写法:
public class JdbcTemplateDao implements AccountDao{
private JdbcTemplate jdbcTemplate;
//只要类中有set方法 在xml文件就可以进行配置和注入
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
...
}
//使用注解进行配置时候的java类中的写法:
@Repository
public class JdbcTemplateDao implements AccountDao {
private JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
....
...
}
注意1:JdbcTemplate模板类如何使用:在htmlsingle中搜索即可,其中包含有大量的使用实例
注意2:spring结合jdbc的时候,不论是否使用这个模板,jdbc操作的事务默认是自动提交的(和之前学习jdbc的时候是一致的)
2、 Spring与mybatis结合
添加整合的相关jar包
1)、原始dao的开发的整合方式
1、接口的实现类
public class AccountDaoImpl implements IAccountDao{
private SqlSessionFactory sqlSessionFactory;
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public void saveAccount(Account acc) {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("com.briup.db.IAccountDao.saveAccount", acc);
}
}
2、mybatis-config.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>
<package name="com.briup.db" />
</typeAliases>
<mappers>
<mapper resource="com/briup/db/mybatis/AccountMapper.xml"/>
</mappers>
</configuration>
3、mybatis的映射文件AccountMapper.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.briup.db.IAccountDao">
<insert id="saveAccount" parameterType="account">
insert into account_tbl values(#{id},#{name},#{balance})
</insert>
</mapper>
4、spring的配置文件
<context:property-placeholder location="oracle.properties"/>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>${driver}</value>
</property>
<property name="url">
<value>${url}</value>
</property>
<property name="username">
<value>${username}</value>
</property>
<property name="password">
<value>${password}</value>
</property>
<!-- 最大连接数 -->
<property name="maxActive">
<value>80</value>
</property>
<!-- 最大空闲连接数 -->
<property name="maxIdle">
<value>20</value>
</property>
<!-- 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间 单位:毫秒 -->
<!-- 超过时间则抛出异常,如果设置为-1表示无限等待 -->
<property name="maxWait">
<value>3000</value>
</property>
</bean>
<!-- 配置sqlsessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 指定mybatis-config总配置文件,订制的environment在spring容器中不在生效-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="accountDao" class="com.briup.db.mybatis.AccountDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
2)、Mapper代码开发的整合方式
1、dao层接口不需要写实现类
2、mybatis-config.xml和mybatis的映射文件AccountMapper.xml和之前一样
3、spring的配置文件
<!-- 配置sqlsessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 指定mybatis-config总配置文件,订制的environment在spring容器中不在生效-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="accountMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.briup.db.IAccountDao"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
test:
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/briup/db/mybatis/mybatis2.xml");
IAccountDao dao = (IAccountDao) ctx.getBean("accountMapper");
dao.saveAccount(new Account(2,"zs",2000));
注:该种mapper代理开发的整合方式,存在一些问题
实际的开发过程中,不可能只有一个AccountMapper,可能还有OtherMapper,等等,不可能将所有的xxMapper都配置一遍,那样也太麻烦了,mybatis的整合包给我们提供了一个扫描类MapperScannerConfigurer,用它就可以了
3)、使用MapperScannerConfigurer
1、dao层接口不需要写实现类
2、mybatis-config.xml和mybatis的映射文件AccountMapper.xml和之前一样
AccountMapper.xml文件要和接口放在同一个包中
3、spring的配置文件
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@172.16.157.130:1521:XE</value>
</property>
<property name="username">
<value>briup</value>
</property>
<property name="password">
<value>briup</value>
</property>
<!-- 最大连接数 -->
<property name="maxActive">
<value>80</value>
</property>
<!-- 最大空闲连接数 -->
<property name="maxIdle">
<value>20</value>
</property>
<!-- 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间 单位:毫秒 -->
<!-- 超过时间则抛出异常,如果设置为-1表示无限等待 -->
<property name="maxWait">
<value>3000</value>
</property>
</bean>
<!-- 配置sqlsessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 指定mybatis-config总配置文件,订制的environment在spring容器中不在生效-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.briup.db"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!-- 通过来扫描mapper接口所在的包名,当有多个包的时候,用半角逗号分隔即可
然后再次强调下,这种方式的配置,AccountMapper.xml必须和对应的接口放在同一个目录下面
-->
———————————————————————
Spring事务管理机制
1)编程式事务管理:所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。
Spring框架提供一致的事务抽象,因此无论对于JDBC还是mybatis的事务都是采用相同的API进行编程。
2)声明式事务管理(declarative transaction management)
Spring提供的对程序事务管理的方式之一,在Spring配置文件中声明式的处理事务来代替代码式的处理事务.
在spring中,声明式事务主要是通过【事务属性】来定义的,事务属性描述了事务策略如何应用到方法上面。
事务属性包含了5个方面:传播行为 隔离级别 回滚规则 事务超时 是否只读
声明式事务管理的配置方式通常以下几种:
注意:配置事务配置的方式都需要用到事务管理器(切面)和事务拦截器(advice)
1使用ProxyFactoryBean给目标对象产生代理对象.
2使用TransactionProxyFactoryBean为目标对象生成事务代理的配置。这是一个专门给目标对象产生管理事务的代理对象的工厂类
3使用DefaultAdvisorAutoProxyCreator自动代理,和BeanNameAutoProxyCreator基本差不多,二者区别参照我们第三天上课的内容.
4使用BeanNameAutoProxyCreator根据beanName给目标对象自动生成事务代理的代理对象,
5使用tx前缀的专门事务标签和aop前缀的标签结合,将切面(事务管理)织入到切入点上(引入新的schema文件和命名空间)
6使用注解进行事务配置
推荐使用第五种:tx标签结合aop标签
注意:
事务属性的传播行为包括:
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
————————————————————————
了解内容:
<prop key="myMethod">PROPAGATION_REQUIRED,readOnly,-Exception</prop>
这样的配置,其中:
-Exception表示有Exception抛出时,事务回滚. -代表回滚+就代表提交
readonly 就是read only, 设置操作权限为只读,一般用于查询的方法,优化作用.
注意:指定事务属性的取值有较复杂的规则。具体的书写规则如下:
传播行为 [,隔离级别] [,只读属性] [,超时属性] [不影响提交的异常] [,导致回滚的异常]
1)事务传播行为
定义了新的事务应该被启动还是被挂起 或者方法是否需要在事务中运行。
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
这里需要指出的是,前面的六种事务传播行为是 Spring 从 EJB 中引入的,他们共享相同的概念。而 PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。如果熟悉 JDBC 中的保存点(SavePoint)的概念,那嵌套事务就很容易理解了,其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,每一个嵌套子事务。另外,外部事务的回滚也会导致嵌套子事务的回滚。
2)事务隔离级别
定义了一个事务可能受其他并发事务影响的程度。
隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
3)事务的只读属性
定义了一个事务中是否是只读操作 如果设置只读那么数据库内部就可以对该操作进行合适的优化措施,只有传播行为是PROPAGATION_REQUIRED PROPAGATION_REQUIRES_NEW PROPAGATION_NESTED的时候只读设置才有意义,因为只读优化是在事务开始的时候由数据库实施的,而在这三个传播行为下才有可能启动一个新事务
4)事务超时
为了使应用程序可以很好的运行,事务不能运行太长的时间,所以这个属性就控制着这个时间.只有传播行为是PROPAGATION_REQUIRED PROPAGATION_REQUIRES_NEW PROPAGATION_NESTED的时候超时设置才有意义,因为超时时钟会在事务开始的时候启动,而在这三个传播行为下才有可能启动一个新事务.注意事务超时后会自动回滚.(单位是 秒)
5)事务的回滚规则
定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务在遇到运行时异常的时候才会回滚,而遇到检查时异常时不会回滚
-Exception表示有Exception抛出时,事务回滚. -代表回滚+就代表提交
1.JDBC与事务的结合
a.bean包中的Account类
b.dao包中IAccountDao接口
public interface IAccountDao {
public void saveAccount(Account acc);
public void selectAccount(Account acc);
}
c.com.briup.tran.service包提供IAccountService接口:
public interface IAccountService {
public void register(Account acc);
}
//
基于dao层,service完成JDBC和myBatis的两种方式的实现方式:
下面是JDBC的实现方式:
//
c.AccountDaoImpl是IAccountDao的实现类
public class AccountDaoImpl implements IAccountDao{
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void saveAccount(Account acc) {
try {
Connection conn = DataSourceUtils.getConnection(dataSource);
// Connection conn = dataSource.getConnection();
System.out.println("saveAccount:"+conn);
PreparedStatement pstmt =
conn.prepareStatement(
"insert into account_tbl values(?,?,?)");
pstmt.setInt(1, acc.getId());
pstmt.setString(2, acc.getName());
pstmt.setDouble(3, acc.getBalance());
int i = pstmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void selectAccount(Account acc) {
// TODO Auto-generated method stub
}
d.提供dao层的spring的配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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">
<!-- 第二种配置数据源 -->
<bean class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
name="dataSource">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@172.16.157.130:1521:XE</value>
</property>
<property name="username">
<value>briup</value>
</property>
<property name="password">
<value>briup</value>
</property>
</bean>
<bean id="accountDao" class="com.briup.tran.jdbc.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
e.提供service的实现类
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void register(Account acc) {
// TODO Auto-generated method stub
accountDao.saveAccount(acc);
int i=10/0;
}
}
f.提供service层的spring的配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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">
<!-- jdbc的事务 相当于切面类-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
name="transactionManager">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
<!-- 目标对象 -->
<bean id="accountService" class="com.briup.tran.jdbc.service.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 配置事务拦截器 (advice) -->
<bean name="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<!--
PROPAGATION_REQUIRED
事务七种属性中的其实一种。表示如果当前有事务
就拿要执行的操作放到这个事务里面,如果当前没有事务
那么就新建一个事务然后把这个操作放进去执行。
-Exception
表示如果操作期间抛出了Exception异常或者是它的子类型异常,
那么当前的事务就回滚,-号代表回滚,如果是+号,代表依然提交。
-->
<property name="transactionAttributes">
<props>
<!-- *代表所有的方法 -->
<prop key="*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
<!-- 代理对象 -->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="accountService">
</property>
<!-- 注入目标对象实现的接口 -->
<property name="proxyInterfaces">
<list>
<value>com.briup.tran.service.IAccountService</value>
</list>
</property>
<!-- 注入advice (也就是上面配置的事务拦截器) -->
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
</beans>
g.提供测试例子
String[] path={"com/briup/tran/jdbc/dao/jdbc_dao.xml",
"com/briup/tran/jdbc/service/jdbc_service.xml"};
ApplicationContext ac=new ClassPathXmlApplicationContext(path);
IAccountService as = (IAccountService) ac.getBean("serviceProxy");
as.register(new Account(5,"tom",10000));
下面是mybatis的事务管理方式
1.不用提供dao层的实现类,
只需要提供映射文件和spring的配置文件
2.提供service层的实现类
3.提供service层的spring的配置文件
a.mybatis_service1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务拦截器 相当于aop配置中advice-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 配置在些方法上面加入哪些事务属性 以及抛出什么异常的时候回滚-->
<tx:method name="register*" propagation="REQUIRED" rollback-for="Throwable"/>
</tx:attributes>
</tx:advice>
<!-- 上面配置了切面类以及advice -->
<!-- 这里就要做aop的配置了 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut id="myPointCut"
expression="execution(* com.briup.tran.mybatis..*.*(..))"/>
<!-- 配置事务拦截器在哪一个切入点上起作用 -->
<aop:advisor pointcut-ref="myPointCut" advice-ref="txAdvice"/>
</aop:config>
</beans>
b.mybatis_service2.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 通知 -->
<bean name="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<!--
PROPAGATION_REQUIRED
事务七种属性中的其实一种。表示如果当前有事务
就拿要执行的操作放到这个事务里面,如果当前没有事务
那么就新建一个事务然后把这个操作放进去执行。
-Exception
表示如果操作期间抛出了Exception异常或者是它的子类型异常,
那么当前的事务就回滚,-号代表回滚,如果是+号,代表依然提交。
-->
<property name="transactionAttributes">
<props>
<!-- *代表所有的方法 -->
<prop key="*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
<!-- 代理对象 -->
<bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 注入目标对象 -->
<property name="target" ref="service"></property>
<!-- 注入目标对象实现的接口 -->
<property name="proxyInterfaces">
<list>
<value>com.briup.tran.service.IAccountService</value>
</list>
</property>
<!-- 注入advice (也就是上面配置的事务拦截器) -->
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
</beans>
c.mybatis_service3.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 这个工厂类中结合了事务拦截器,所以我们就不需要配事务拦截器 -->
<bean name="proxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 注入目标对象 -->
<property name="target" ref="service"></property>
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<!--
PROPAGATION_REQUIRED
事务七种属性中的其实一种。表示如果当前有事务
就拿要执行的操作放到这个事务里面,如果当前没有事务
那么就新建一个事务然后把这个操作放进去执行。
-Exception
表示如果操作期间抛出了Exception异常或者是它的子类型异常,
那么当前的事务就回滚,-号代表回滚,如果是+号,代表依然提交。
-->
<property name="transactionAttributes">
<props>
<!-- *代表所有的方法 -->
<prop key="*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
</beans>
d.mybatis_service4.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean name="proxyAbstract" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<!--
PROPAGATION_REQUIRED
事务七种属性中的其实一种。表示如果当前有事务
就拿要执行的操作放到这个事务里面,如果当前没有事务
那么就新建一个事务然后把这个操作放进去执行。
-Exception
表示如果操作期间抛出了Exception异常或者是它的子类型异常,
那么当前的事务就回滚,-号代表回滚,如果是+号,代表依然提交。
-->
<property name="transactionAttributes">
<props>
<!-- *代表所有的方法 -->
<prop key="*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
<bean name="proxy" parent="proxyAbstract">
<property name="target" ref="service"></property>
</bean>
</beans>
e.mybatis_service5.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务拦截器 (advice) -->
<bean name="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<!--
PROPAGATION_REQUIRED
事务七种属性中的其实一种。表示如果当前有事务
就拿要执行的操作放到这个事务里面,如果当前没有事务
那么就新建一个事务然后把这个操作放进去执行。
-Exception
表示如果操作期间抛出了Exception异常或者是它的子类型异常,
那么当前的事务就回滚,-号代表回滚,如果是+号,代表依然提交。
-->
<property name="transactionAttributes">
<props>
<!-- *代表所有的方法 -->
<prop key="*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
<!-- 配置代理对象 -->
<bean name="autoproxybyname"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>service</value>
</list>
</property>
<property name="interceptorNames">
<value>transactionInterceptor</value>
</property>
</bean>
</beans>
f.mybatis_service6.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
1 Spring与jdbc结合
jdbc编程不变,主要是Connection对象的维护,即配置并使用数据源
1) <!-- 基于jdk的规范数据源 -->
<bean name="dataSource1"
class="oracle.jdbc.pool.OracleConnectionPoolDataSource">
<property name="networkProtocol">
<value>tcp</value>
</property>
<property name="databaseName">
<value>XE</value>
</property>
<property name="driverType">
<value>thin</value>
</property>
<property name="portNumber">
<value>1521</value>
</property>
<property name="user">
<value>briup</value>
</property>
<property name="serverName">
<value>127.0.0.1</value>
</property>
<property name="password">
<value>briup</value>
</property>
</bean>
注意:别忘了读取配置文件
<!-- 读取这个资源文件 读完之后下面就可以用${key}来去文件中的value值了 -->
<!-- 这种方式是我们第一节学习的那种配置方式方式的简写 -->
<context:property-placeholder location="com/briup/db/jdbc/jdbc.properties"/>
2) <!-- dbcp数据源 -->
<bean id="dataSource2"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>${jdbc.driverClassName}</value>
</property>
<property name="url">
<value>${jdbc.url}</value>
</property>
<property name="username">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<!-- 最大连接数 -->
<property name="maxActive">
<value>80</value>
</property>
<!-- 最大空闲连接数 -->
<property name="maxIdle">
<value>20</value>
</property>
<!-- 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间 单位:毫秒 -->
<!-- 超过时间则抛出异常,如果设置为-1表示无限等待 -->
<property name="maxWait">
<value>3000</value>
</property>
</bean>
3) <!-- spring提供的一种数据源 -->
<bean id="dataSource3"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${jdbc.driverClassName}</value>
</property>
<property name="url">
<value>${jdbc.url}</value>
</property>
<property name="username">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
spring在jdbc的使用中还给我们提供了一个模板类:JdbcTemplate
用以简化我们的jdbc操作
例如:
//使用xml进行配置时候的java类中的写法:
public class JdbcTemplateDao implements AccountDao{
private JdbcTemplate jdbcTemplate;
//只要类中有set方法 在xml文件就可以进行配置和注入
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
...
}
//使用注解进行配置时候的java类中的写法:
@Repository
public class JdbcTemplateDao implements AccountDao {
private JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
....
...
}
注意1:JdbcTemplate模板类如何使用:在htmlsingle中搜索即可,其中包含有大量的使用实例
注意2:spring结合jdbc的时候,不论是否使用这个模板,jdbc操作的事务默认是自动提交的(和之前学习jdbc的时候是一致的)
2、 Spring与mybatis结合
添加整合的相关jar包
1)、原始dao的开发的整合方式
1、接口的实现类
public class AccountDaoImpl implements IAccountDao{
private SqlSessionFactory sqlSessionFactory;
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public void saveAccount(Account acc) {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("com.briup.db.IAccountDao.saveAccount", acc);
}
}
2、mybatis-config.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>
<package name="com.briup.db" />
</typeAliases>
<mappers>
<mapper resource="com/briup/db/mybatis/AccountMapper.xml"/>
</mappers>
</configuration>
3、mybatis的映射文件AccountMapper.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.briup.db.IAccountDao">
<insert id="saveAccount" parameterType="account">
insert into account_tbl values(#{id},#{name},#{balance})
</insert>
</mapper>
4、spring的配置文件
<context:property-placeholder location="oracle.properties"/>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>${driver}</value>
</property>
<property name="url">
<value>${url}</value>
</property>
<property name="username">
<value>${username}</value>
</property>
<property name="password">
<value>${password}</value>
</property>
<!-- 最大连接数 -->
<property name="maxActive">
<value>80</value>
</property>
<!-- 最大空闲连接数 -->
<property name="maxIdle">
<value>20</value>
</property>
<!-- 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间 单位:毫秒 -->
<!-- 超过时间则抛出异常,如果设置为-1表示无限等待 -->
<property name="maxWait">
<value>3000</value>
</property>
</bean>
<!-- 配置sqlsessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 指定mybatis-config总配置文件,订制的environment在spring容器中不在生效-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="accountDao" class="com.briup.db.mybatis.AccountDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
2)、Mapper代码开发的整合方式
1、dao层接口不需要写实现类
2、mybatis-config.xml和mybatis的映射文件AccountMapper.xml和之前一样
3、spring的配置文件
<!-- 配置sqlsessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 指定mybatis-config总配置文件,订制的environment在spring容器中不在生效-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="accountMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.briup.db.IAccountDao"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
test:
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/briup/db/mybatis/mybatis2.xml");
IAccountDao dao = (IAccountDao) ctx.getBean("accountMapper");
dao.saveAccount(new Account(2,"zs",2000));
注:该种mapper代理开发的整合方式,存在一些问题
实际的开发过程中,不可能只有一个AccountMapper,可能还有OtherMapper,等等,不可能将所有的xxMapper都配置一遍,那样也太麻烦了,mybatis的整合包给我们提供了一个扫描类MapperScannerConfigurer,用它就可以了
3)、使用MapperScannerConfigurer
1、dao层接口不需要写实现类
2、mybatis-config.xml和mybatis的映射文件AccountMapper.xml和之前一样
AccountMapper.xml文件要和接口放在同一个包中
3、spring的配置文件
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@172.16.157.130:1521:XE</value>
</property>
<property name="username">
<value>briup</value>
</property>
<property name="password">
<value>briup</value>
</property>
<!-- 最大连接数 -->
<property name="maxActive">
<value>80</value>
</property>
<!-- 最大空闲连接数 -->
<property name="maxIdle">
<value>20</value>
</property>
<!-- 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间 单位:毫秒 -->
<!-- 超过时间则抛出异常,如果设置为-1表示无限等待 -->
<property name="maxWait">
<value>3000</value>
</property>
</bean>
<!-- 配置sqlsessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 指定mybatis-config总配置文件,订制的environment在spring容器中不在生效-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.briup.db"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!-- 通过来扫描mapper接口所在的包名,当有多个包的时候,用半角逗号分隔即可
然后再次强调下,这种方式的配置,AccountMapper.xml必须和对应的接口放在同一个目录下面
-->
———————————————————————
Spring事务管理机制
1)编程式事务管理:所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。
Spring框架提供一致的事务抽象,因此无论对于JDBC还是mybatis的事务都是采用相同的API进行编程。
2)声明式事务管理(declarative transaction management)
Spring提供的对程序事务管理的方式之一,在Spring配置文件中声明式的处理事务来代替代码式的处理事务.
在spring中,声明式事务主要是通过【事务属性】来定义的,事务属性描述了事务策略如何应用到方法上面。
事务属性包含了5个方面:传播行为 隔离级别 回滚规则 事务超时 是否只读
声明式事务管理的配置方式通常以下几种:
注意:配置事务配置的方式都需要用到事务管理器(切面)和事务拦截器(advice)
1使用ProxyFactoryBean给目标对象产生代理对象.
2使用TransactionProxyFactoryBean为目标对象生成事务代理的配置。这是一个专门给目标对象产生管理事务的代理对象的工厂类
3使用DefaultAdvisorAutoProxyCreator自动代理,和BeanNameAutoProxyCreator基本差不多,二者区别参照我们第三天上课的内容.
4使用BeanNameAutoProxyCreator根据beanName给目标对象自动生成事务代理的代理对象,
5使用tx前缀的专门事务标签和aop前缀的标签结合,将切面(事务管理)织入到切入点上(引入新的schema文件和命名空间)
6使用注解进行事务配置
推荐使用第五种:tx标签结合aop标签
注意:
事务属性的传播行为包括:
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
————————————————————————
了解内容:
<prop key="myMethod">PROPAGATION_REQUIRED,readOnly,-Exception</prop>
这样的配置,其中:
-Exception表示有Exception抛出时,事务回滚. -代表回滚+就代表提交
readonly 就是read only, 设置操作权限为只读,一般用于查询的方法,优化作用.
注意:指定事务属性的取值有较复杂的规则。具体的书写规则如下:
传播行为 [,隔离级别] [,只读属性] [,超时属性] [不影响提交的异常] [,导致回滚的异常]
1)事务传播行为
定义了新的事务应该被启动还是被挂起 或者方法是否需要在事务中运行。
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
这里需要指出的是,前面的六种事务传播行为是 Spring 从 EJB 中引入的,他们共享相同的概念。而 PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。如果熟悉 JDBC 中的保存点(SavePoint)的概念,那嵌套事务就很容易理解了,其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,每一个嵌套子事务。另外,外部事务的回滚也会导致嵌套子事务的回滚。
2)事务隔离级别
定义了一个事务可能受其他并发事务影响的程度。
隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
3)事务的只读属性
定义了一个事务中是否是只读操作 如果设置只读那么数据库内部就可以对该操作进行合适的优化措施,只有传播行为是PROPAGATION_REQUIRED PROPAGATION_REQUIRES_NEW PROPAGATION_NESTED的时候只读设置才有意义,因为只读优化是在事务开始的时候由数据库实施的,而在这三个传播行为下才有可能启动一个新事务
4)事务超时
为了使应用程序可以很好的运行,事务不能运行太长的时间,所以这个属性就控制着这个时间.只有传播行为是PROPAGATION_REQUIRED PROPAGATION_REQUIRES_NEW PROPAGATION_NESTED的时候超时设置才有意义,因为超时时钟会在事务开始的时候启动,而在这三个传播行为下才有可能启动一个新事务.注意事务超时后会自动回滚.(单位是 秒)
5)事务的回滚规则
定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务在遇到运行时异常的时候才会回滚,而遇到检查时异常时不会回滚
-Exception表示有Exception抛出时,事务回滚. -代表回滚+就代表提交
1.JDBC与事务的结合
a.bean包中的Account类
b.dao包中IAccountDao接口
public interface IAccountDao {
public void saveAccount(Account acc);
public void selectAccount(Account acc);
}
c.com.briup.tran.service包提供IAccountService接口:
public interface IAccountService {
public void register(Account acc);
}
//
基于dao层,service完成JDBC和myBatis的两种方式的实现方式:
下面是JDBC的实现方式:
//
c.AccountDaoImpl是IAccountDao的实现类
public class AccountDaoImpl implements IAccountDao{
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void saveAccount(Account acc) {
try {
Connection conn = DataSourceUtils.getConnection(dataSource);
// Connection conn = dataSource.getConnection();
System.out.println("saveAccount:"+conn);
PreparedStatement pstmt =
conn.prepareStatement(
"insert into account_tbl values(?,?,?)");
pstmt.setInt(1, acc.getId());
pstmt.setString(2, acc.getName());
pstmt.setDouble(3, acc.getBalance());
int i = pstmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void selectAccount(Account acc) {
// TODO Auto-generated method stub
}
d.提供dao层的spring的配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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">
<!-- 第二种配置数据源 -->
<bean class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
name="dataSource">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@172.16.157.130:1521:XE</value>
</property>
<property name="username">
<value>briup</value>
</property>
<property name="password">
<value>briup</value>
</property>
</bean>
<bean id="accountDao" class="com.briup.tran.jdbc.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
e.提供service的实现类
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void register(Account acc) {
// TODO Auto-generated method stub
accountDao.saveAccount(acc);
int i=10/0;
}
}
f.提供service层的spring的配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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">
<!-- jdbc的事务 相当于切面类-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
name="transactionManager">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
<!-- 目标对象 -->
<bean id="accountService" class="com.briup.tran.jdbc.service.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 配置事务拦截器 (advice) -->
<bean name="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<!--
PROPAGATION_REQUIRED
事务七种属性中的其实一种。表示如果当前有事务
就拿要执行的操作放到这个事务里面,如果当前没有事务
那么就新建一个事务然后把这个操作放进去执行。
-Exception
表示如果操作期间抛出了Exception异常或者是它的子类型异常,
那么当前的事务就回滚,-号代表回滚,如果是+号,代表依然提交。
-->
<property name="transactionAttributes">
<props>
<!-- *代表所有的方法 -->
<prop key="*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
<!-- 代理对象 -->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="accountService">
</property>
<!-- 注入目标对象实现的接口 -->
<property name="proxyInterfaces">
<list>
<value>com.briup.tran.service.IAccountService</value>
</list>
</property>
<!-- 注入advice (也就是上面配置的事务拦截器) -->
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
</beans>
g.提供测试例子
String[] path={"com/briup/tran/jdbc/dao/jdbc_dao.xml",
"com/briup/tran/jdbc/service/jdbc_service.xml"};
ApplicationContext ac=new ClassPathXmlApplicationContext(path);
IAccountService as = (IAccountService) ac.getBean("serviceProxy");
as.register(new Account(5,"tom",10000));
下面是mybatis的事务管理方式
1.不用提供dao层的实现类,
只需要提供映射文件和spring的配置文件
2.提供service层的实现类
3.提供service层的spring的配置文件
a.mybatis_service1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务拦截器 相当于aop配置中advice-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 配置在些方法上面加入哪些事务属性 以及抛出什么异常的时候回滚-->
<tx:method name="register*" propagation="REQUIRED" rollback-for="Throwable"/>
</tx:attributes>
</tx:advice>
<!-- 上面配置了切面类以及advice -->
<!-- 这里就要做aop的配置了 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut id="myPointCut"
expression="execution(* com.briup.tran.mybatis..*.*(..))"/>
<!-- 配置事务拦截器在哪一个切入点上起作用 -->
<aop:advisor pointcut-ref="myPointCut" advice-ref="txAdvice"/>
</aop:config>
</beans>
b.mybatis_service2.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 通知 -->
<bean name="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<!--
PROPAGATION_REQUIRED
事务七种属性中的其实一种。表示如果当前有事务
就拿要执行的操作放到这个事务里面,如果当前没有事务
那么就新建一个事务然后把这个操作放进去执行。
-Exception
表示如果操作期间抛出了Exception异常或者是它的子类型异常,
那么当前的事务就回滚,-号代表回滚,如果是+号,代表依然提交。
-->
<property name="transactionAttributes">
<props>
<!-- *代表所有的方法 -->
<prop key="*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
<!-- 代理对象 -->
<bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 注入目标对象 -->
<property name="target" ref="service"></property>
<!-- 注入目标对象实现的接口 -->
<property name="proxyInterfaces">
<list>
<value>com.briup.tran.service.IAccountService</value>
</list>
</property>
<!-- 注入advice (也就是上面配置的事务拦截器) -->
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
</beans>
c.mybatis_service3.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 这个工厂类中结合了事务拦截器,所以我们就不需要配事务拦截器 -->
<bean name="proxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 注入目标对象 -->
<property name="target" ref="service"></property>
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<!--
PROPAGATION_REQUIRED
事务七种属性中的其实一种。表示如果当前有事务
就拿要执行的操作放到这个事务里面,如果当前没有事务
那么就新建一个事务然后把这个操作放进去执行。
-Exception
表示如果操作期间抛出了Exception异常或者是它的子类型异常,
那么当前的事务就回滚,-号代表回滚,如果是+号,代表依然提交。
-->
<property name="transactionAttributes">
<props>
<!-- *代表所有的方法 -->
<prop key="*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
</beans>
d.mybatis_service4.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean name="proxyAbstract" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<!--
PROPAGATION_REQUIRED
事务七种属性中的其实一种。表示如果当前有事务
就拿要执行的操作放到这个事务里面,如果当前没有事务
那么就新建一个事务然后把这个操作放进去执行。
-Exception
表示如果操作期间抛出了Exception异常或者是它的子类型异常,
那么当前的事务就回滚,-号代表回滚,如果是+号,代表依然提交。
-->
<property name="transactionAttributes">
<props>
<!-- *代表所有的方法 -->
<prop key="*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
<bean name="proxy" parent="proxyAbstract">
<property name="target" ref="service"></property>
</bean>
</beans>
e.mybatis_service5.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务拦截器 (advice) -->
<bean name="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<!--
PROPAGATION_REQUIRED
事务七种属性中的其实一种。表示如果当前有事务
就拿要执行的操作放到这个事务里面,如果当前没有事务
那么就新建一个事务然后把这个操作放进去执行。
-Exception
表示如果操作期间抛出了Exception异常或者是它的子类型异常,
那么当前的事务就回滚,-号代表回滚,如果是+号,代表依然提交。
-->
<property name="transactionAttributes">
<props>
<!-- *代表所有的方法 -->
<prop key="*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
<!-- 配置代理对象 -->
<bean name="autoproxybyname"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>service</value>
</list>
</property>
<property name="interceptorNames">
<value>transactionInterceptor</value>
</property>
</bean>
</beans>
f.mybatis_service6.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<!-- 目标对象 -->
<bean id="service" class="com.briup.tran.mybatis.service.AccountServiceImpl">
</bean>
<!-- 事务处理类 相当与一个切面类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>