Spring笔记04_AOP注解开发_模板_事务
1. Spring基于AspectJ的注解的AOP开发
1. 1 SpringAOP的注解入门
创建项目,导入jar包
需要导入Spring基础包4+2
需要导入AOP联盟包、AspectJ包、Spring整合Aspect包Spring-aop包
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>
编写目标类并配置
package com.itzhouq.spring.demo1; public class OrderDao {
public void save() {
System.out.println("保存订单。。。");
}
public void update() {
System.out.println("修改订单。。。");
}
public void find() {
System.out.println("查找订单。。。");
}
public String delete() {
System.out.println("删除订单。。。");
return "周杰伦";
}
}
配置目标类,将目标类OrderDao交给Spring管理
- 在applicationContext.xml中添加
<!-- 配置目标类 -->
<bean id="orderDao" class="com.itzhouq.spring.demo1.OrderDao"></bean>
编写切面类并配置
package com.itzhouq.spring.demo1;
/*
* 切面类:注解的切面类
*/
public class MyAspectAnno { public void before() {
System.out.println("前置增强===============");
}
}
<!-- 配置切面类 -->
<bean id="myAspect" class="com.itzhouq.spring.demo1.MyAspectAnno"></bean>
使用注解的AOP对目标类的方法进行增强
首先在配置文件中打开注解的AOP开发
<!-- 在配置文件总开启注解的AOP开发 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
在切面类上使用注解
/*
* 切面类:注解的切面类
*/
@Aspect //标记该类为切面类
public class MyAspectAnno { @Before(value="execution(* com.itzhouq.spring.demo1.OrderDao.save(..))")
public void before() {//这个注解用来标记目标类的哪个方法使用何种增强
System.out.println("前置增强===============");
}
}
测试
package com.itzhouq.spring.demo1; import javax.annotation.Resource; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /*
* Spring的AOP注解开发测试
*/ @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo1 {
@Resource(name="orderDao") //注入OrderDao
private OrderDao orderDao; @Test
public void test1() {
orderDao.save();
orderDao.update();
orderDao.find();
orderDao.delete();
// 前置增强===============
// 保存订单。。。
// 修改订单。。。
// 查找订单。。。
// 删除订单。。。 }
}
1.2 Spring的AOP的注解通知类型
1.2.1 @Before:前置通知
1.2.2 @AfterReturning:后置通知
在删除delete方法上使用后置通知
在切面类中添加以下方法
//后置通知
@AfterReturning("execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))")
public void afterReturning() {
System.out.println("后置增强==================");
}
不用修改目标类直接测试就能实现效果
前置增强===============
保存订单。。。
修改订单。。。
查找订单。。。
删除订单。。。
后置增强==================
后置通知还可以使用返回值
//后置通知
@AfterReturning(value="execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))", returning="result")
public void afterReturning(Object result) {
System.out.println("后置增强=================="+result);
}
前置增强===============
保存订单。。。
修改订单。。。
查找订单。。。
删除订单。。。
后置增强==================周杰伦
1.2.3 环绕通知
在切面类中添加以下方法:
//环绕通知
@Around(value="execution(* com.itzhouq.spring.demo1.OrderDao.update(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕前增强===========");
Object obj = joinPoint.proceed();
System.out.println("环绕前增强===========");
return obj;
}
测试
前置增强===============
保存订单。。。
环绕前增强===========
修改订单。。。
环绕前增强===========
查找订单。。。
删除订单。。。
后置增强==================周杰伦
1.2.4 异常抛出通知
异常抛出通知可以获得异常信息
在切面类中添加方法
//异常抛出通知
@AfterThrowing(value="execution(* com.itzhouq.spring.demo1.OrderDao.find(..))",throwing="e")
public void afterThrowing(Throwable e) {
System.out.println("异常抛出通知============"+e);
}
在find方法中模拟异常
public void find() {
System.out.println("查找订单。。。");
int i = 1 / 0;
}
测试
前置增强===============
保存订单。。。
环绕前增强===========
修改订单。。。
环绕前增强===========
查找订单。。。
异常抛出通知============java.lang.ArithmeticException: / by zero
1.2.5 最终通知‘
在切面类中添加方法
//最终通知
@After(value="execution(* com.itzhouq.spring.demo1.OrderDao.find(..))")
public void after() {
System.out.println("最终增强============");
}
测试
前置增强===============
保存订单。。。
环绕前增强===========
修改订单。。。
环绕前增强===========
查找订单。。。
最终增强============
异常抛出通知============java.lang.ArithmeticException: / by zero
1.3 Spring的AOP的注解的切入点的注解
修改切面类
package com.itzhouq.spring.demo1; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut; /*
* 切面类:注解的切面类
*/
@Aspect //标记该类为切面类
public class MyAspectAnno { @Before(value="MyAspectAnno.pointcut2()")
public void before() {//这个注解用来标记目标类的哪个方法使用何种增强
System.out.println("前置增强===============");
} //后置通知
@AfterReturning(value="execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))", returning="result")
public void afterReturning(Object result) {
System.out.println("后置增强=================="+result);
} //环绕通知
@Around(value="MyAspectAnno.pointcut3()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕前增强===========");
Object obj = joinPoint.proceed();
System.out.println("环绕前增强===========");
return obj;
} //异常抛出通知
@AfterThrowing(value="MyAspectAnno.pointcut4()",throwing="e")
public void afterThrowing(Throwable e) {
System.out.println("异常抛出通知============"+e);
} //最终通知
@After(value="MyAspectAnno.pointcut1()")
public void after() {
System.out.println("最终增强============");
} //切入点注解
@Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.find(..))")
private void pointcut1() {}
@Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.save(..))")
private void pointcut2() {}
@Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.update(..))")
private void pointcut3() {}
@Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))")
private void pointcut4() {}
}
- 通过切入点的注解,可以简化注解的代码量
- 注意:使用类名.pointcut1()时候不要忘记pointcut1()是一个方法,需要带上()才有效
2. Spring的JDBC的模板的使用
2.1 Spring的JDBC的模板
Spring的EE开发的一站式的框架,有EE开发中每一层的解决方案。Spring对持久层也提供了解决方案:ORM模块和JDBC的模块。
Spring提供了很多的模板用于简化开发。
2.1.1 JDBC模板使用的入门
创建项目,引入jar包
引入基本的4+2包
数据库驱动包
Spring的JDBC模板的jar包:事务管理tx和jdbc的包
单元测试包
创建数据库和表
create database spring4_day03;
use spring4_day03;
create table account(
id int primary key auto_increment,
name varchar(20),
money double
)
使用JDBC模板:保存数据
package com.itzhouq.spring.jdbc.demo1; import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource; /*
* JDBC的模板使用
*/
public class JdbcDemo1 {
@Test //JDBC的模板的使用类似于Dbutils
public void test1() {
//创建连接池 这里使用Spring默认的连接池
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring4_day03");
dataSource.setUsername("root");
dataSource.setPassword("2626"); //创建jdbc模板
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("insert into account values (null, ?,?)", "周杰伦",10000d);
} }
将日志记录的配置文件jdbc.properties拷贝到src下
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring4_day03
jdbc.username=root
jdbc.password=2626
测试能插入数据
2.1.2 将连接池和模板交给Spring管理
引入aop的jar包
引入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的内置连接池,将连接池交给Spring管理
<!-- 配置Spring的内置连接池 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 属性注入 ===============-->
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///spring4_day03"></property>
<property name="username" value="root"></property>
<property name="password" value="2626"></property>
</bean>
配置Spring的jdbc模板,将模板交给Spring管理
<!-- 配置Spring的JDBC模板 =================-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
使用JDBC的模板
package com.itzhouq.spring.jdbc.demo1; import javax.annotation.Resource; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value="classpath:applicationContext.xml")
public class JdbcDemo2 {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate; @Test
public void test1() {
jdbcTemplate.update("insert into account values (null, ?,?)", "赵雷",10000d);
}
}
测试能插入数据
2.2 使用开源的数据库连接池
2.2.1 C3P0的使用
导入jar包
- com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
路径
- ..\spring-framework-3.0.2.RELEASE-dependencies\com.mchange.c3p0\com.springsource.com.mchange.v2.c3p0
配置C3P0连接池
<!-- 配置C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 属性注入 =============== -->
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///spring4_day03"></property>
<property name="user" value="root"></property>
<property name="password" value="2626"></property>
</bean>
<!-- 配置Spring的JDBC模板 =================-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
- 注意:C3P0连接池的核心类是:com.mchange.v2.c3p0.ComboPooledDataSource
- 测试能插入数据
2.2.2 DBCP的使用
引入jar包
- com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
- com.springsource.org.apache.commons.pool-1.5.3.jar
路径
- ..\spring-framework-3.0.2.RELEASE-dependencies\org.apache.commons\com.springsource.org.apache.commons.dbcp
- ..\spring-framework-3.0.2.RELEASE-dependencies\org.apache.commons\com.springsource.org.apache.commons.pool
配置DBCP的连接池
<!-- 配置DBCP连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
属性注入 ===============
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///spring4_day03"></property>
<property name="username" value="root"></property>
<property name="password" value="2626"></property>
</bean> <!-- 配置Spring的JDBC模板 =================-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
注意:DBCP的核心类为
org.apache.commons.dbcp.BasicDataSource
。测试能插入数据
2.3 抽取配置到属性文件
在src下新建配置文件jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring4_day03
jdbc.username=root
jdbc.password=2626
在Spring的配置文件中引入属性文件
<!-- 引入连接数据的属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置C3P0连接池 -->
<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>
测试能插入数据
2.4 使用JDBC模板进行CURD操作
2.4.1 增
package com.itzhouq.spring.jdbc.demo1;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value="classpath:applicationContext.xml")
public class JdbcDemo2 {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void test1() {
jdbcTemplate.update("insert into account values (null, ?,?)", "YYY",10000d);
}
}
2.4.2 删
@Test
public void test3() {//删除
jdbcTemplate.update("delete from account where id = ?", 5);
}
2.4.3 改
@Test
public void test2() {//修改
jdbcTemplate.update("update account set name = ?, money = ? where id = ?", "何巨涛",10000d, 6);
}
2.4.4 查
查询某个属性
@Test
public void test4() {//查询某个属性
String name = jdbcTemplate.queryForObject("select name from account where id = ?", String.class, 6);
System.out.println(name);
}
查询个数
@Test
public void test5() {//查询个数
Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
System.out.println(count);
}
返回的是对象
首先要创建一个实体Account
@Test
public void test6() {//封装到一个对象中
Account account = jdbcTemplate.queryForObject("select * from account where id = ?", new MyRowMapper(), 4);
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.setMoney(rs.getDouble("money"));
return account;
}
}
queryForObject的第二个参数需要实现一个接口RowMapper
查询多条记录
@Test
public void test7() {
List<Account> listAccount = jdbcTemplate.query("select * from account", new MyRowMapper());
for (Account account : listAccount) {
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.setMoney(rs.getDouble("money"));
return account;
}
}
3. Spring的事务管理
3.1 事务的回顾
3.1.1 什么是事务
- 事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。
3.1.2 事务的特性
- 原子性:事务不可分割
- 一致性:事务执行前后数据完整性保持一致
- 隔离性:一个事务的执行不应该受到其他事务的影响
- 持久性:一旦事务结束,数据就持久化到数据库中
3.1.3 不考虑事务的隔离性引发安全问题
- 读问题
- 脏读:一个事务读到另一个事务未提交的数据
- 不可重复读:一个事务读取到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致
- 虚读、幻读:一个事务读到另一个事务已经提交的insert数据,导致一个事务中多次查询结果不一致
- 写问题
- 丢失更新
3.1.4 解决读问题
- 设置事务的隔离级别
- read uncommited:未提交读,任何读问题都解决不了
- Read commited:已提交读,解决脏读,但是不可重复读和虚读有可能发生
- Repeatable read:重复读,解决脏读和不可重复读,但是虚读有可能发生
- Serializable:解决所有读问题
3.2 Spring的事务管理的API
3.2. 1 PlatformTransactionManager:平台事务管理器
- 平台事务管理器:接口,是Spring用于管理事务的真正的对象。
- DataSourceTransactionManager:底层使用JDBC管理事务
- HibernateTransactionManager:底层使用Hibernate管理事务
3.2.2 TransactionDefinition:事务定义信息
- 事务定义:用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读
3.2.3 TransactionStatus:事务的状态
- l 事务状态:用于记录在事务管理过程中,事务的状态的对象。
3.2.4 事务管理的API的关系
- Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。
3.3 事务的传播行为
- Spring中提供了七种事务的传播行为
3.3.1 保证多个操作在同一个事务中
- PROPAGATION_REQUIRED:默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来
- PROPAGATION_SUPPORTS:支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
- PROPAGATION_MANDATORY:如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。
3.3.2 保证多个操作不在同一个事务中
- PROPAGATION_REQUIRES_NEW:如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。
- PROPAGATION_NOT_SUPPORTED:如果A中有事务,将A的事务挂起。不使用事务管理。
- PROPAGATION_NEVER:如果A中有事务,报异常。
3.3.3 嵌套式事务
- PROPAGATION_NESTED:嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。
3.4 事务的管理
3.4.1 案例:转账
创建AccountService接口
package com.itzhouq.spring.tx.demo1;
/*
* 转账的业务层的接口
*/
public interface AccountService {
public void transfer(String from, String to, Double money);
}
创建接口实现类AccountServiceImpl
package com.itzhouq.spring.tx.demo1;
/*
* 转账的业务层的实现类
*/
public class AccountServiceImpl implements AccountService { //注入DAO
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
} /**
* from:转出账户
* to:转入账户
* money:转账金额
*/
@Override
public void transfer(String from, String to, Double money) {
accountDao.outMoney(from, money);
int i = 1 / 0;
accountDao.inMoney(to, money);
}
}
创建AccountDao接口
package com.itzhouq.spring.tx.demo1;
/*
* 转账的DAO的接口
*/
public interface AccountDao {
public void outMoney(String from, Double money);
public void inMoney(String to, Double money);
}
创建AccountDao实现类AccountDaoImpl
package com.itzhouq.spring.tx.demo1; import org.springframework.jdbc.core.support.JdbcDaoSupport; public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override
public void outMoney(String from, Double money) {
this.getJdbcTemplate().update("update account set money=money-? where name=?", money,from);
} @Override
public void inMoney(String to, Double money) {
this.getJdbcTemplate().update("update account set money=money+? where name=?", money,to);
}
}
配置Service和Dao:交给Spring管理
复制applicationContext.xml文件,新建配置文件tx.xml
<!-- 配置Service -->
<bean id="accountService" class="com.itzhouq.spring.tx.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean> <!-- 配置Dao -->
<bean id="accountDao" class="com.itzhouq.spring.tx.demo1.AccountDaoImpl"> </bean>
在Dao中编写扣钱和加钱
配置连接池和JDBC的模板
<!-- 引入连接数据的属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置C3P0连接池 -->
<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>
<!-- 配置Spring的JDBC模板 =================-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
在Dao中注入jdbc的模板
方法一:在Dao中直接注入
package com.itzhouq.spring.tx.demo1; import org.springframework.jdbc.core.JdbcTemplate; public class AccountDaoImpl implements AccountDao { private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
} @Override
public void outMoney(String from, Double money) { } @Override
public void inMoney(String to, Double money) { }
}
方法二:AccountDaoImpl继承JdbcDaoSupport
JdbcDaoSupport类中提供了模板,也提供了set方法
package com.itzhouq.spring.tx.demo1; import org.springframework.jdbc.core.support.JdbcDaoSupport; public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override
public void outMoney(String from, Double money) { } @Override
public void inMoney(String to, Double money) { }
}
所以直接在xml文件中的dao注入模板
<!-- 配置Dao -->
<bean id="accountDao" class="com.itzhouq.spring.tx.demo1.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
方法三:继承JdbcDaoSupport类之后直接注入连接池,这样连接池可以自动创建模板
不用配置模板,直接dao中注入连接池
<!--可以省略的配置-->
<!-- 配置Spring的JDBC模板 =================-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置Dao -->
<bean id="accountDao" class="com.itzhouq.spring.tx.demo1.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
配置文件
<?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"> <!-- 配置Service -->
<bean id="accountService" class="com.itzhouq.spring.tx.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean> <!-- 配置Dao -->
<bean id="accountDao" class="com.itzhouq.spring.tx.demo1.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean> <!-- 引入连接数据的属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置C3P0连接池 -->
<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>
<!-- 配置Spring的JDBC模板 =================-->
<!-- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean> --> </beans>
测试
package com.itzhouq.spring.tx.demo1; import javax.annotation.Resource; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /*
* 测试转账
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:tx.xml")
public class SpringDemo1 {
@Resource(name="accountService")
private AccountService accountService; @Test
public void test1() {
accountService.transfer("周杰伦", "邓超", 1000d);
}
}
- 如果没有异常能够转账成功。但是没有事务控制,一旦转账过程中出现异常就会出现数据丢失的现象。
3.4.2 Spring的事务管理
- 方式一:编程式事务,需要手动编码【了解】
- 方式二:声明式事务,通过配置实现---AOP
3.4.3 声明式事务
XML方式的声明式的事务管理
引入jar包
aop联盟包
aspectJ包
aop包
Spring整合aspectJ包
配置事务管理器
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
配置增强
<!-- 配置事务的增强=============================== -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 事务管理的规则 -->
<!-- <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true"/> -->
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
</tx:attributes>
</tx:advice>
AOP的配置
<!-- aop的配置 -->
<aop:config>
<aop:pointcut expression="execution(* com.itzhouq.spring.tx.demo1.AccountServiceImpl.*(..))" id="pointcut1"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
- 测试:如果转账出现异常,事务自动回滚
注解方式声明事务
引入aop的开发包
配置事务管理
<!-- 配置事务管理器=============================== -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
开启注解事务
<!-- 开启注解事务================================ -->
<tx:annotation-driven transaction-manager="transactionManager"/>
在业务层添加注解
@Transactional
public class AccountServiceImpl implements AccountService {测试:如果转账过程中出现异常,则自动回滚。
Spring笔记04_AOP注解开发_模板_事务的更多相关文章
- Spring笔记13--SSH--全注解开发
SSH全注解开发: (1) 在Action类中添加注解,实现Struts2的注解开发(@NameSpace.@ParentPackage.@Action...) package com.tongji. ...
- spring boot纯注解开发模板
简介 spring boot纯注解开发模板 创建项目 pom.xml导入所需依赖 点击查看源码 <dependencies> <dependency> <groupId& ...
- Spring---AOP注解开发&jdbc模板&Spring事务管理
一.AOP注解开发 此处需要回忆一遍AOP的概念.简单的来说,AOP就是利用动态代理技术,做到不触动源代码但却扩展了功能.那么就需要一个被扩展的对象和一个“新的功能”,例如说给某类的saveUser方 ...
- Spring入门(三)— AOP注解、jdbc模板、事务
一.AOP注解开发 导入jar包 aop联盟包. aspectJ实现包 . spring-aop-xxx.jar . spring-aspect-xxx.jar 导入约束 aop约束 托管扩展类和被扩 ...
- Spring笔记02_注解_IOC
目录 Spring笔记02 1. Spring整合连接池 1.1 Spring整合C3P0 1.2 Spring整合DBCP 1.3 最终版 2. 基于注解的IOC配置 2.1 导包 2.2 配置文件 ...
- Spring的IOC注解开发入门1
基本知识点如下: 引入注解约束,配置组件扫描 类上的注解: @Conponent @Controller @Service @Repository 普通属性的注解 @value 对象属性的注解 ...
- Spring的IOC注解开发入门2
注解方式设置属性的值 在我们IOC基于xml属性注入的方式中有(一般推荐set方法) 构造方法注入普通值:<constructor-arg>的使用 set方法注入普通值:<prope ...
- spring MVC之注解开发控制器(二)
开发表单控制器 在传统的Spring MVC开发方法中,是通过扩展SimpleFormController类来创建简单的表单控制器.这样就定义了基本的表单处理流程,并允许通过覆盖几个生命周期方法来定制 ...
- spring笔记--通过注解(annotation)配置Bean
Spring能够在classpath下自动扫描,侦测和实例化具有特定注解的组件,这在Spring中成为组件扫描(Component scanning). 特定组件的注解包括: @Component:基 ...
随机推荐
- centos7下搭建高匿HTTP代理
一.一般适用情况1.两台都有外网IP,一台服务器请求资源通过另外一个服务器,本文重点讲第一种.2.两台服务器,其中一台服务器只有内网IP,另外一台服务器有公网和内网IP. 二.前提 # 确认服务器端i ...
- python从入门到实践-4章操作列表
magicians = ['alice','david','carolina']for magician in magicians: print(magician) print(magician.ti ...
- 玩转vue前进刷新,后退不刷新and按需刷新
大白萝卜小课堂开讲了!带你玩转vue前进后退按需刷新! 用vue做后台管理项目,特别是有列表页.列表数据详情页.列表数据修改页功能的码友们,几乎都被vue前进后退都刷新的逻辑坑过,本萝卜更是! 萝卜的 ...
- CABaRet: Leveraging Recommendation Systems for Mobile Edge Caching
CABaRet:利用推荐系统进行移动边缘缓存 本文为SIGCOMM 2018 Workshop (Mobile Edge Communications, MECOMM)论文. 笔者翻译了该论文.由于时 ...
- 【RL-TCPnet网络教程】第22章 RL-TCPnet之网络协议IP
第22章 RL-TCPnet之网络协议IP 本章节为大家讲解IP(Internet Protocol,网络协议),通过前面章节对TCP和UDP的学习,需要大家对IP也有个基础的认识. (本章 ...
- 基于Spring Boot、Spring Cloud、Docker的微服务系统架构实践
由于最近公司业务需要,需要搭建基于Spring Cloud的微服务系统.遍访各大搜索引擎,发现国内资料少之又少,也难怪,国内Dubbo正统治着天下.但是,一个技术总有它的瓶颈,Dubbo也有它捉襟见肘 ...
- admui框架使用经验
刚开始接触admui框架时确实有些迷茫,不知道怎么使用,摸索了一段时间后才发现这个框架很简单!以下是我遇见的一些坑,总结一下啦! 1.使用框架第一步就是开启服务器,我给公司写项目时开启的是5000端口 ...
- 说一说MVC的过滤器(一)
在MVC项目中过滤器,最好把这些过滤器类放到一个文件夹中(Filters),然后过滤器文件的名称也是有规定的,格式应该为xxxAttribute,否则在控制器或控制器的方法中是无法进行调用过滤器的, ...
- redis 系列5 数据结构之字典(上)
一. 概述 字典又称符号表(symbol table),关联数组(associative array), 映射(map),是一种用于保存键值对(key-value pair)的抽象数据结构.在字典中, ...
- 从零开始学习PYTHON3讲义(六)for循环跟斐波那契数列
<从零开始PYTHON3>第六讲 几乎但凡接触过一点编程的人都知道for循环,在大多数语言的学习中,这也是第一个要学习的循环模式. 但是在Python中,我们把for循环放到了while循 ...