Spring对DAO的增强体现在Dao对数据库的操作上(通俗的讲就是使用一个jdbc的模板)
Spring对Service层的增强体现在对事务的管理上,通过aop的思想将事务很好的整合了
一.Spring的AOP的注解入门
(一) AOP对DAO的增强
1. 创建web项目,引入jar包
2. 创建相关的包和类
- 创建包com.cdut.aop.demo1,创建接口:
public interface CustomerDao {
public void save();
public void update();
public void find();
public Integer delete();
}
- 创建类CustomerDaoImpl.java
public class CustomerDaoImpl implements CustomerDao {
@Override
public void save() {
System.out.println("这是一个=保存=客户的方法");
}
@Override
public void update() {
System.out.println("这是一个=更新=客户的方法");
}
@Override
public void find() {
System.out.println("这是一个=查找=客户的方法");
}
@Override
public Integer delete() {
System.out.println("这是一个=删除=客户的方法");
return null;
}
}
3. 编写切面类,并且完成配置
@Aspect
public class MyAspectAnno {
//方式一:在自定义的切面类里面讲通知和切点绑定
@Before("MyAspectAnno.pointcut1() || MyAspectAnno.pointcut2()")
public void before(){
System.out.println("this is 前置");
}
@Pointcut("execution(* com.cdut.spring.demon.CustomerDaoImpl.save(..))")
private void pointcut1(){};
@Pointcut("execution(* com.cdut.spring.demon.CustomerDaoImpl.update(..))")
private void pointcut2(){};
//方式二: 直接在通知上织入
@After("execution(* com.cdut.spring.demon.CustomerDaoImpl.find(..)))")
public void after(){
System.out.println("这个是后置的增强");
}
}
4. 创建核心配置文件,配置实现类
src创建applicationContext.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: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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
<!--开启自动代理 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--配置目标类: 其实就是CustomerDaoImpl -->
<bean id="customerDao" class="com.cdut.spring.demon.CustomerDaoImpl"> </bean>
<!-- 配置切面类 -->
<bean id="myAspectAnno" class="com.cdut.spring.demon.MyAspectAnno"></bean>
</beans>
5.编写测试类
注意Spring和JUnit的整合
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demon {
//注入一个CustomerDao对象
@Resource(name="customerDao")
private CustomerDao customerDao;
@Test
public void test01(){
customerDao.find();
customerDao.save();
customerDao.update();
customerDao.delete();
}
}
6. 输出结果显示
这是一个=查找=客户的方法
这个是后置的增强
this is 前置
这是一个=保存=客户的方法
this is 前置
这是一个=更新=客户的方法
这是一个=删除=客户的方法
7.总结
这个小案例是使用Spring的AOP思想对DAO的一种增强.
- Spring的AOP思想就是代理模式的体现–横向编程
流程分析:
首先是编写基本的类,注意在编写切面类的是后需要将通知和切点进行绑定
第一种方式:先将通知和一个自定义的切点的绑定, 再将自定义的切点和连接点进行绑定
第二种方式:一步到位 直接在通知上面将连接点绑定 不用去自定义一个切点了
然后在配置文件中开启自动代理. 将目标类和 切面类配置进去
最后编写一个测试类进行测试
(二) Spring的AOP的注解通知
1 其他通知的使用
- 前置通知、后置通知、环绕通知、异常通知、后置通知
@Aspect
public class MyAspectAnno {
@Before("execution(* com.cdut.spring.demon.CustomerDaoImpl.save(..))")
public void before(JoinPoint joinpoint){
System.out.println("前置增强==========");
}
@AfterReturning(value="execution(* com.cdut.spring.demon.CustomerDaoImpl.delete(..))",returning="result")
public void afterReturning(JoinPoint joinpoint,Object result){
System.out.println("后置增强=========="+result);
}
@AfterThrowing(value="execution(* com.cdut.spring.demon.CustomerDaoImpl.find(..))",throwing="ex")
public void afterThrowing(JoinPoint joinpoint,Throwable ex){
System.out.println("异常抛出增强======"+ex.getMessage());
}
@After(value="execution(* com.cdut.spring.demon.CustomerDaoImpl.find(..))")
public void after(JoinPoint joinpoint){
System.out.println("最终通知========");
}
@Around(value="execution(* com.cdut.spring.demon.CustomerDaoImpl.update(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕前增强========");
Object obj = joinPoint.proceed();
System.out.println("环绕后增强========");
return obj;
}
}
二. Spring中的事务管理(对Service层的优化)
(一) Spring的JDBC的模板
- Spring称为是EE开发一站式框架,有EE开发每层解决方案。Spring对持久层提供了JDBC 模板和ORM模板。
1. Spring的JDBC的模板入门
- 创建工程、引入jar包
- 创建数据库和表
- 创建数据库:myspring
- 创建表 account
- id
- name
- price
- 编写测试类
public class JDBCTemplateDemon1 {
@Test
public void test01(){
//创建一个数据源
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///myspring");
dataSource.setUsername("root");
dataSource.setPassword("123");
//在模板中注入数据源,就可以连接数据库
JdbcTemplate template = new JdbcTemplate();
template.setDataSource(dataSource);
template.update("insert into account values(?,?,?)", null,"东野圭吾",10000d);
}
}
2. 将连接池的信息交给Spring管理
- 配置applicationContext.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: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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
- 配置连接池
<!-- 配置Spring的内置连接池 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///myspring"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</bean>
<!-- 配置JDBC的模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
- 测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JDBCTemplateDemon2 {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void test01(){
jdbcTemplate.update("insert into account values(?,?,?)",null,"热巴",200000d);
}
}
3. 配置DBCP连接池:
<!-- 配置DBCP连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///myspring"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</bean>
4. 配置C3P0连接池:
<!-- 配置C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///myspring"/>
<property name="user" value="root"/>
<property name="password" value="123"/>
</bean>
5. 信息保存到属性文件中
- 将数据库的信息放到jdbc.properties中
- 定义属性文件jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///myspring
jdbc.username=root
jdbc.password=123
- 在配置文件中引入属性文件
- 方案一:通过bean标签引入的
<!-- 引入外部属性文件的方式一 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
方案二:通过context标签引入的(推荐)
<!-- 引入外部属性文件的方式二-->
<context:property-placeholder location="classpath:jdbc.properties"/>
- 修改连接池的配置${},加载属性文件的名称
<!-- 配置连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JDBCTemplateDemon2 {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void test01(){
jdbcTemplate.update("insert into account values(?,?,?)",null,"Rita",20000d);
}
}
6. JDBC模板完成CRUD的操作
- 增删改的方法
update(String sql,Object… args);
- 查询的方法
T queryForObject(String sql,Class<T> requiredType,Object… args);
T queryForObject(String sql,RowMapper<T> rowMapper,Object… args);
List<T> query(String sql,RowMapper<T>,Object… args);
- 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JDBCTemplateDemo2 {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void demo1(){
jdbcTemplate.update("insert into account values (?,?,?)",null,"思想",10000d);
}
@Test
public void demo2(){
jdbcTemplate.update("update account set name = ? , money = ? where id = ?","傻瓜",20000d,5);
}
@Test
public void demo3(){
jdbcTemplate.update("delete from account where id = ?",5);
}
@Test
public void demo4(){
String name = jdbcTemplate.queryForObject("select name from account where id = ?", String.class, 1);
System.out.println(name);
}
@Test
public void demo5(){
Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
System.out.println(count);
}
@Test
public void demo6(){
Account account = jdbcTemplate.queryForObject("select * from account where id = ?", new MyRowMapper(), 1);
System.out.println(account);
}
@Test
public void demo7(){
List<Account> list = jdbcTemplate.query("select * from account", new MyRowMapper());
for (Account account : list) {
System.out.println(account);
}
}
//重点
class MyRowMapper implements RowMapper<Account>{
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setPrice(rs.getDouble("price"));
return account;
}
}
}
7.总结
- 关于JDBC的模板,就是建立一个数据源,将这个数据源注入到模板中就可以使用了
- 将信息保存到一个配置文件中
- 在xml中引入这个文件
- 然后配置一个连接池
- 再配置一个JDBC模板,将连接池注入
- 注意一下接受参数时需要自己实现一个接口
(二) Spring的事务的管理
1 事务的回顾
- 事务的概念
- 事务是逻辑上一组操作,组成这组操作各个逻辑单元,要么一起成功,要么一起失败。
- 事务的特性(ACID)
- 原子性
- 一致性
- 隔离性
- 持久性
- 读问题
- 脏读
- 不可重复读
- 幻读
脏读:一个事务读取了另一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的。
不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务已提交的更新(update)数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样,也就是,后续读取不能读到另一事务已提交的更新数据。
幻读(幻读):一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了。再后来的查询中,第一个事务就会发现有些原来没有的记录。
- 设置事务隔离级别
- read uncommitted
- read committed(oracle默认)
- repeatable read(mysql默认)
- Serializable
隔离级别 | 含义 |
---|---|
READ_UNCOMMITED | 允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读 |
READ_COMMITTED | 允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生 |
REPEATABLE_READ | 对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。 |
SERIALIZABLE | 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。 |
2. Spring的事务管理的API
PlatformTransactionManager :平台事务管理器,是Spring真正管理事务对象。
- DataSourceTransactionManager :针对JDBC事务管理
- HibernateTransactionManager :针对Hibernate事务管理
TransactionDefinition :事务定义
- 事务隔离级别
隔离级别 | 含义 |
---|---|
DEFAULT | 使用后端数据库默认的隔离级别(spring中的的选择项) |
READ_UNCOMMITED | 允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读 |
READ_COMMITTED | 允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生 |
REPEATABLE_READ | 对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。 |
SERIALIZABLE | 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。 |
- 事务传播行为(往下看)
- 事务是否只读
事务超时信息
- TransactionStatus :事务状态信息
- 是否有保存点
- 是否已经完成
- 是否已经回滚
总结:
Spring框架进行事务的管理,首先使用TransactionDefinition对事务进行定义(选择操作数据库的方式)。通过PlatformTransactionManager(JDBC、HIbernate)根据TransactionDefinition(隔离级别、传播行为、是否只读、是否超时)的定义信息进行事务的管理。在事务管理过程中产生一系列的状态:保存到TransactionStatus(是否提交、是否回滚)中。
3. Spring的事务管理:传播行为
传播行为用来解决哪些问题
- 用来解决复杂的事务操作,没有,一个还是多个事务
事务传播行为的取值:
-
PROPAGATION_REQUIRED 传播行为的默认值。如果A中有事务,使用A中的事务。如果A没有事务,新建事务。 PROPAGATION_SUPPORTS 如果A中有事务,就使用A中的事务,如果A没有事务,就不使用事务。 PROPAGATION_MANDATORY 如果A中有事务,就使用A中的事务,如果A没有事务,报错。 PROPAGATION_REQUIREDS_NEW 如果A中有事务,将A中的事务挂起。创建一个新的事务。 PROPAGATION_NOT_SUPPORED 如果A中有事务,将A中事务挂起。非事务运行。 PROPAGATION_NEVER 如果A中有事务,就报错。 PROPAGATION_NESTED 使用嵌套事务。在A执行完毕后设置一个保存点,如果B中执行没问题,就执行通过,如果有异常,允许使用者回滚到保存点或者是回滚到最初始状态。
4. Spring的事务管理分类
- Spring的编程式事务管理 :手动编写代码实现事务管理
- 在实际应用中很少使用,原因是要修改原来的代码,加入事务管理代码 (侵入性 )
- Spring的声明式事务管理 :通过配置实现事务管理
- XML的声明式事务管理
- 注解的声明式事务管理
- 开发中经常使用声明式事务管理(代码侵入性最小)--推荐使用!
- 不需要修改业务层的代码,也不需要手动添加transactionManager.commit(),也不需要手动添加transactionManager.rollback(),更不需要使用try…catch…,这一切都被封装好了,我们只需要配置就可以了。
(三) 搭建转账环境
1. 创建项目,引入jar包,导入数据
需求:账号转账,Tom账号取出1000元,存放到Jack账号上
- 第一步:创建表account
- 第二步:插入测试数据:
- 第三步:查看测试数据:
2 在xml中配置
<bean id="customerDao" class="com.cdut.jdbc.dao.impl.CustomerDaoImpl"></bean>
<bean id="customerService" class="com.cdut.jdbc.service.impl.CustomerServiceImpl"></bean>
<!-- 配置JDBC的模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
<!-- 配置连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
3 编写和配置DAO
定义AccountDao.java
public class CustomerDaoImpl implements CustomerDao {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void outMoney(String outName, Double moneny) {
jdbcTemplate.update("update account set price = price - ? where name = ?", moneny,outName);
}
@Override
public void inMoney(String inName, Double moneny) {
jdbcTemplate.update("update account set price = price + ? where name = ?",moneny,inName);
}
}
4 编写和配置Service
public class CustomerServiceImpl implements CustomerService {
@Resource(name="customerDao")
private CustomerDao customerDao;
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}
@Override
public void deal(String inName, String outName, Double moneny) {
customerDao.outMoney(outName, moneny);
customerDao.inMoney(inName, moneny);
}
}
5 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class demon01 {
@Resource(name="customerService")
private CustomerService customerService;
@Test
public void test01(){
customerService.deal("rose", "jake", 1000.0);
}
@Test
public void test02(){
customerService.deal("jake", "rose", 1000.0);
}
}
!! Spring的编程式事务管理(了解)
1 配置事务管理器
Jdbc的操作,需要配置Jdbc的事务管理器
配置applicationContext-tx1.xml
<!-- 配置事务管理器=============== -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"
ref="dataSource"/>
</bean>
2 配置事务管理模板
配置applicationContext-tx1.xml
<!-- 配置事务管理的模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager"
ref="transactionManager"/>
</bean>
3 在业务层注入事务管理模板
配置applicationContext-tx1.xml
<!-- 配置Service -->
<bean id="accountService" class="com.cdut.tx.demo1.AccountServiceImpl">
<property name=*"accountDao" ref="accountDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
4 改写业务层的代码
AccountServiceImpl.java
@Override
public void transfer(final String from, final String to, final Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
accountDao.outMoney(from, money);
int d = 1/0;
accountDao.inMoney(to, money);
}
});
}
问题;代码具有侵入性,开发效率很慢。
!!!!! (一) Spring的声明式事务管理:XML方式(AOP思想)
1 引入aop的jar包
2 恢复转账环境
3 导入Dao和Service
4 配置数据源
<!-- 引入外部属性文件的方式二 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
5 配置事务管理器
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
6 配置事务
<!-- 配置事务的增强 :规定事务管理的标准-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true"/>
<!-- 配置具体的方法的事务属性
isolation//事务的隔离级别,默认是按数据库的隔离级别来
propagation//事务的传播行为,默认是同一个事务
timeout="-1":事务的超时时间,默认值使用数据库的超时时间。-1表示不会超时,timeout超时时间如果设置为2秒,也就是说发生事务回滚后,2秒钟后对用户响应。
read-only="false":事务是否只读,默认可读写。
rollback-for:遇到哪些异常就回滚,其他的都不回滚
no-rollback-for:遇到哪些异常不回滚,其他的都回滚。和上面互斥的
测试:no-rollback-for="java.lang.ArithmeticException",遇到算数异常不回滚
-->
-->
<tx:method name="deal" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
7 进行AOP的增强
<!-- 配置AOP -->
<aop:config>
<aop:pointcut expression="execution(* com.cdut.jdbc.CustomerServiceImpl.deal(..))" id="pointcut1"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
8 编写测试类
9 声明式事务的原理
通过aop思想生成了代理类, 通过代理类来增强了原来的类再执行代理类
10 总结
大概流程
- 想要在service层插入事务,根据aop的原理来讲,需要先在xml中创建一个通知集(事务管理器,也就是我理解的切面), 事务管理器创建好了就要配置事务(从事务管理器中取出一个具体的事务),然后在aop配置中将切点找到, 与拿出来的事务进行绑定.
在xml需要编写的代码
- 引入约束
- 注册dao
- 注册service
- 引入jdbc配置文件
- 配置c3p0连接池(数据源)
- 注册jdbc的模板(在dao层执行数据库的操作)
- 注册事务管理器
- 配置事务
- 进行aop的增强
!!!!! (二) Spring的声明式事务的管理:注解方式
1 恢复开发环境
2 导入Dao、Service
3 在xml中配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
4. service层
public class CustomerServiceImpl implements CustomerService {
@Resource(name="customerDao")
private CustomerDao customerDao;
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}
@Override
@Transactional
public void deal(String inName, String outName, Double moneny) {
customerDao.outMoney(outName, moneny);
customerDao.inMoney(inName, moneny);
}
}
或者在类上加上一个@Transactional
5.总结
相比xml的开发模式, 注解开发显得更加方便
在xml中配置一个事务管理器
开启事务注解
在service层中的类上或者方法上配置一个@Transactional 在这个@Transactional中可以配置想要的事务的级别