Spring笔记04

mac2022-06-30  18

目录

1. Spring基于AspectJ的注解的AOP开发 1. 1 SpringAOP的注解入门1.2 Spring的AOP的注解通知类型 1.2.1 @Before:前置通知1.2.2 @AfterReturning:后置通知1.2.3 环绕通知1.2.4 异常抛出通知1.2.5 最终通知‘1.3 Spring的AOP的注解的切入点的注解2. Spring的JDBC的模板的使用 2.1 Spring的JDBC的模板 2.1.1 JDBC模板使用的入门2.1.2 将连接池和模板交给Spring管理2.2 使用开源的数据库连接池 2.2.1 C3P0的使用2.2.2 DBCP的使用2.3 抽取配置到属性文件2.4 使用JDBC模板进行CURD操作 2.4.1 增2.4.2 删2.4.3 改2.4.4 查3. Spring的事务管理 3.1 事务的回顾 3.1.1 什么是事务3.1.2 事务的特性3.1.3 不考虑事务的隔离性引发安全问题3.1.4 解决读问题3.2 Spring的事务管理的API 3.2. 1 PlatformTransactionManager:平台事务管理器3.2.2 TransactionDefinition:事务定义信息3.2.3 TransactionStatus:事务的状态3.2.4 事务管理的API的关系3.3 事务的传播行为 3.3.1 保证多个操作在同一个事务中3.3.2 保证多个操作不在同一个事务中3.3.3 嵌套式事务3.4 事务的管理 3.4.1 案例:转账3.4.2 Spring的事务管理3.4.3 声明式事务

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.jarcom.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 {

测试:如果转账过程中出现异常,则自动回滚。

转载于:https://www.cnblogs.com/itzhouq/p/spring04.html

相关资源:spring中AOP 注解开发示例详解
最新回复(0)