1. Spring基于AspectJ的注解的AOP開發(fā)
1. 1 SpringAOP的注解入門
-
創(chuàng)建項目确买,導(dǎo)入jar包
需要導(dǎo)入Spring基礎(chǔ)包4+2
需要導(dǎo)入AOP聯(lián)盟包、AspectJ包瞧预、Spring整合Aspect包Spring-aop包
-
Spring整合單元測試包
image
-
引入配置文件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>
-
編寫目標(biāo)類并配置
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 "周杰倫"; } }
-
配置目標(biāo)類虑绵,將目標(biāo)類OrderDao交給Spring管理
- 在applicationContext.xml中添加
<!-- 配置目標(biāo)類 --> <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對目標(biāo)類的方法進行增強
-
首先在配置文件中打開注解的AOP開發(fā)
<!-- 在配置文件總開啟注解的AOP開發(fā) --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
在切面類上使用注解
/* * 切面類:注解的切面類 */ @Aspect //標(biāo)記該類為切面類 public class MyAspectAnno { @Before(value="execution(* com.itzhouq.spring.demo1.OrderDao.save(..))") public void before() {//這個注解用來標(biāo)記目標(biāo)類的哪個方法使用何種增強 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注解開發(fā)測試 */ @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("后置增強=================="); }
-
不用修改目標(biāo)類直接測試就能實現(xiàn)效果
前置增強=============== 保存訂單骤铃。。坷剧。 修改訂單惰爬。。惫企。 查找訂單撕瞧。。狞尔。 刪除訂單丛版。。偏序。 后置增強==================
-
后置通知還可以使用返回值
//后置通知 @AfterReturning(value="execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))", returning="result") public void afterReturning(Object result) { System.out.println("后置增強=================="+result); }
前置增強=============== 保存訂單页畦。。研儒。 修改訂單豫缨。。端朵。 查找訂單好芭。。逸月。 刪除訂單栓撞。。碗硬。 后置增強==================周杰倫
1.2.3 環(huán)繞通知
-
在切面類中添加以下方法:
//環(huán)繞通知 @Around(value="execution(* com.itzhouq.spring.demo1.OrderDao.update(..))") public Object around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("環(huán)繞前增強==========="); Object obj = joinPoint.proceed(); System.out.println("環(huán)繞前增強==========="); return obj; }
-
測試
前置增強=============== 保存訂單瓤湘。。恩尾。 環(huán)繞前增強=========== 修改訂單弛说。。翰意。 環(huán)繞前增強=========== 查找訂單木人。。冀偶。 刪除訂單醒第。。进鸠。 后置增強==================周杰倫
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; }
-
測試
前置增強=============== 保存訂單霞幅。漠吻。。 環(huán)繞前增強=========== 修改訂單司恳。途乃。。 環(huán)繞前增強=========== 查找訂單扔傅。耍共。。 異常拋出通知============java.lang.ArithmeticException: / by zero
1.2.5 最終通知‘
-
在切面類中添加方法
//最終通知 @After(value="execution(* com.itzhouq.spring.demo1.OrderDao.find(..))") public void after() { System.out.println("最終增強============"); }
-
測試
前置增強=============== 保存訂單铅鲤。划提。枫弟。 環(huán)繞前增強=========== 修改訂單邢享。。淡诗。 環(huán)繞前增強=========== 查找訂單骇塘。。韩容。 最終增強============ 異常拋出通知============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 //標(biāo)記該類為切面類 public class MyAspectAnno { @Before(value="MyAspectAnno.pointcut2()") public void before() {//這個注解用來標(biāo)記目標(biāo)類的哪個方法使用何種增強 System.out.println("前置增強==============="); } //后置通知 @AfterReturning(value="execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))", returning="result") public void afterReturning(Object result) { System.out.println("后置增強=================="+result); } //環(huán)繞通知 @Around(value="MyAspectAnno.pointcut3()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("環(huán)繞前增強==========="); Object obj = joinPoint.proceed(); System.out.println("環(huán)繞前增強==========="); 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開發(fā)的一站式的框架群凶,有EE開發(fā)中每一層的解決方案插爹。Spring對持久層也提供了解決方案:ORM模塊和JDBC的模塊。
-
Spring提供了很多的模板用于簡化開發(fā)请梢。
image
2.1.1 JDBC模板使用的入門
-
創(chuàng)建項目赠尾,引入jar包
引入基本的4+2包
數(shù)據(jù)庫驅(qū)動包
Spring的JDBC模板的jar包:事務(wù)管理tx和jdbc的包
-
單元測試包
image
-
創(chuàng)建數(shù)據(jù)庫和表
create database spring4_day03; use spring4_day03; create table account( id int primary key auto_increment, name varchar(20), money double )
-
使用JDBC模板:保存數(shù)據(jù)
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() { //創(chuàng)建連接池 這里使用Spring默認(rèn)的連接池 DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql:///spring4_day03"); dataSource.setUsername("root"); dataSource.setPassword("2626"); //創(chuàng)建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
測試能插入數(shù)據(jù)
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的內(nèi)置連接池,將連接池交給Spring管理
<!-- 配置Spring的內(nèi)置連接池 --> <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); } }
測試能插入數(shù)據(jù)
2.2 使用開源的數(shù)據(jù)庫連接池
2.2.1 C3P0的使用
-
導(dǎo)入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
- 測試能插入數(shù)據(jù)
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
气嫁。測試能插入數(shù)據(jù)
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的配置文件中引入屬性文件
<!-- 引入連接數(shù)據(jù)的屬性文件 --> <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>
測試能插入數(shù)據(jù)
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); }
-
查詢個數(shù)
@Test public void test5() {//查詢個數(shù) Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class); System.out.println(count); }
-
返回的是對象
-
首先要創(chuàng)建一個實體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的第二個參數(shù)需要實現(xiàn)一個接口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的事務(wù)管理
3.1 事務(wù)的回顧
3.1.1 什么是事務(wù)
- 事務(wù):邏輯上的一組操作厘灼,組成這組操作的各個單元灾票,要么全都成功,要么全都失敗术幔。
3.1.2 事務(wù)的特性
- 原子性:事務(wù)不可分割
- 一致性:事務(wù)執(zhí)行前后數(shù)據(jù)完整性保持一致
- 隔離性:一個事務(wù)的執(zhí)行不應(yīng)該受到其他事務(wù)的影響
- 持久性:一旦事務(wù)結(jié)束元咙,數(shù)據(jù)就持久化到數(shù)據(jù)庫中
3.1.3 不考慮事務(wù)的隔離性引發(fā)安全問題
- 讀問題
- 臟讀:一個事務(wù)讀到另一個事務(wù)未提交的數(shù)據(jù)
- 不可重復(fù)讀:一個事務(wù)讀取到另一個事務(wù)已經(jīng)提交的update的數(shù)據(jù)梯影,導(dǎo)致一個事務(wù)中多次查詢結(jié)果不一致
- 虛讀、幻讀:一個事務(wù)讀到另一個事務(wù)已經(jīng)提交的insert數(shù)據(jù)庶香,導(dǎo)致一個事務(wù)中多次查詢結(jié)果不一致
- 寫問題
- 丟失更新
3.1.4 解決讀問題
- 設(shè)置事務(wù)的隔離級別
- read uncommited:未提交讀甲棍,任何讀問題都解決不了
- Read commited:已提交讀,解決臟讀脉课,但是不可重復(fù)讀和虛讀有可能發(fā)生
- Repeatable read:重復(fù)讀救军,解決臟讀和不可重復(fù)讀财异,但是虛讀有可能發(fā)生
- Serializable:解決所有讀問題
3.2 Spring的事務(wù)管理的API
3.2. 1 PlatformTransactionManager:平臺事務(wù)管理器
- 平臺事務(wù)管理器:接口,是Spring用于管理事務(wù)的真正的對象唱遭。
- DataSourceTransactionManager:底層使用JDBC管理事務(wù)
- HibernateTransactionManager:底層使用Hibernate管理事務(wù)
3.2.2 TransactionDefinition:事務(wù)定義信息
- 事務(wù)定義:用于定義事務(wù)的相關(guān)的信息戳寸,隔離級別、超時信息拷泽、傳播行為疫鹊、是否只讀
3.2.3 TransactionStatus:事務(wù)的狀態(tài)
- l 事務(wù)狀態(tài):用于記錄在事務(wù)管理過程中,事務(wù)的狀態(tài)的對象司致。
3.2.4 事務(wù)管理的API的關(guān)系
- Spring進行事務(wù)管理的時候拆吆,首先平臺事務(wù)管理器根據(jù)事務(wù)定義信息進行事務(wù)的管理,在事務(wù)管理過程中脂矫,產(chǎn)生各種狀態(tài)枣耀,將這些狀態(tài)的信息記錄到事務(wù)狀態(tài)的對象中。
3.3 事務(wù)的傳播行為
- Spring中提供了七種事務(wù)的傳播行為
3.3.1 保證多個操作在同一個事務(wù)中
- PROPAGATION_REQUIRED:默認(rèn)值庭再,如果A中有事務(wù)捞奕,使用A中的事務(wù),如果A沒有拄轻,創(chuàng)建一個新的事務(wù)颅围,將操作包含進來
- PROPAGATION_SUPPORTS:支持事務(wù),如果A中有事務(wù)恨搓,使用A中的事務(wù)院促。如果A沒有事務(wù),不使用事務(wù)斧抱。
- PROPAGATION_MANDATORY:如果A中有事務(wù)常拓,使用A中的事務(wù)。如果A沒有事務(wù)夺姑,拋出異常墩邀。
3.3.2 保證多個操作不在同一個事務(wù)中
- PROPAGATION_REQUIRES_NEW:如果A中有事務(wù),將A的事務(wù)掛起(暫停)盏浙,創(chuàng)建新事務(wù)眉睹,只包含自身操作。如果A中沒有事務(wù)废膘,創(chuàng)建一個新事務(wù)竹海,包含自身操作。
- PROPAGATION_NOT_SUPPORTED:如果A中有事務(wù)丐黄,將A的事務(wù)掛起斋配。不使用事務(wù)管理。
- PROPAGATION_NEVER:如果A中有事務(wù),報異常艰争。
3.3.3 嵌套式事務(wù)
- PROPAGATION_NESTED:嵌套事務(wù)坏瞄,如果A中有事務(wù),按照A的事務(wù)執(zhí)行甩卓,執(zhí)行完成后鸠匀,設(shè)置一個保存點,執(zhí)行B中的操作逾柿,如果沒有異常缀棍,執(zhí)行通過,如果有異常机错,可以選擇回滾到最初始位置爬范,也可以回滾到保存點。
3.4 事務(wù)的管理
3.4.1 案例:轉(zhuǎn)賬
-
創(chuàng)建AccountService接口
package com.itzhouq.spring.tx.demo1; /* * 轉(zhuǎn)賬的業(yè)務(wù)層的接口 */ public interface AccountService { public void transfer(String from, String to, Double money); }
-
創(chuàng)建接口實現(xiàn)類AccountServiceImpl
package com.itzhouq.spring.tx.demo1; /* * 轉(zhuǎn)賬的業(yè)務(wù)層的實現(xiàn)類 */ public class AccountServiceImpl implements AccountService { //注入DAO private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } /** * from:轉(zhuǎn)出賬戶 * to:轉(zhuǎn)入賬戶 * money:轉(zhuǎn)賬金額 */ @Override public void transfer(String from, String to, Double money) { accountDao.outMoney(from, money); int i = 1 / 0; accountDao.inMoney(to, money); } }
-
創(chuàng)建AccountDao接口
package com.itzhouq.spring.tx.demo1; /* * 轉(zhuǎn)賬的DAO的接口 */ public interface AccountDao { public void outMoney(String from, Double money); public void inMoney(String to, Double money); }
-
創(chuàng)建AccountDao實現(xiàn)類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管理
-
復(fù)制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的模板
<!-- 引入連接數(shù)據(jù)的屬性文件 --> <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類之后直接注入連接池,這樣連接池可以自動創(chuàng)建模板
-
不用配置模板痢法,直接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> <!-- 引入連接數(shù)據(jù)的屬性文件 --> <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; /* * 測試轉(zhuǎn)賬 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:tx.xml") public class SpringDemo1 { @Resource(name="accountService") private AccountService accountService; @Test public void test1() { accountService.transfer("周杰倫", "鄧超", 1000d); } }
- 如果沒有異常能夠轉(zhuǎn)賬成功狱窘。但是沒有事務(wù)控制杜顺,一旦轉(zhuǎn)賬過程中出現(xiàn)異常就會出現(xiàn)數(shù)據(jù)丟失的現(xiàn)象财搁。
3.4.2 Spring的事務(wù)管理
- 方式一:編程式事務(wù),需要手動編碼【了解】
- 方式二:聲明式事務(wù)躬络,通過配置實現(xiàn)---AOP
3.4.3 聲明式事務(wù)
-
XML方式的聲明式的事務(wù)管理
-
引入jar包
aop聯(lián)盟包
aspectJ包
aop包
-
Spring整合aspectJ包
image
-
配置事務(wù)管理器
<!-- 配置事務(wù)管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
-
配置增強
<!-- 配置事務(wù)的增強=============================== --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 事務(wù)管理的規(guī)則 --> <!-- <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>
- 測試:如果轉(zhuǎn)賬出現(xiàn)異常尖奔,事務(wù)自動回滾
-
-
注解方式聲明事務(wù)
引入aop的開發(fā)包
-
配置事務(wù)管理
<!-- 配置事務(wù)管理器=============================== --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
-
開啟注解事務(wù)
<!-- 開啟注解事務(wù)================================ --> <tx:annotation-driven transaction-manager="transactionManager"/>
-
在業(yè)務(wù)層添加注解
@Transactional public class AccountServiceImpl implements AccountService {
測試:如果轉(zhuǎn)賬過程中出現(xiàn)異常,則自動回滾穷当。