一. IOC 和 DI
IOC : 控制反转,将对象的创建权反转给了 Spring。
DI : 依赖注入,前提是必须要有 IOC 的环境,Spring 管理这个类的时候将类的依赖的属性注入(设置)进来。
二. 工厂类
// 1. 加载类路径 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.save(); // 2. 加载磁盘中的 文件路径 ApplicationContext applicationContext = new FileSystemXmlApplicationContext("C:/Users/Administrator/Desktop/applicationContext.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.save();
三. Bean 的作用范围配置 (xml 文件中)
1. scope : Bean 的作用范围。
! - singleton : 默认,Spring 会采用单例模式创建这个对象。
! - prototype : 多例模式。(Struts2 和 Spring 整合时会用到)
- request : 应用在 Web 项目中,Spring 创建这个类以后,将这个类存入到 request 范围中。
- session : 应用在 Web 项目中,Spring 创建这个类以后,将这个类存入到 session 范围中。
- globalsession : 应用在 Web 项目中,必须在 porlet 环境下使用,如果没有这个环境,相对于 session。
四. Spring 的属性注入方式(xml)
1. 构造方法
// 构造方法 (需要提供构造器)
<!-- 1. 构造方法 --> <bean id="shop" class="com.q.spring.demo2.ShopDao"> <constructor-arg name="name" value="apple" /> <constructor-arg name="price" value="100" /> </bean>
@Test public void demo1(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); ShopDao shopDao = (ShopDao) applicationContext.getBean("shop"); System.out.println(shopDao); }
2. set 方式的属性注入
<!-- 2. set 方法 --> <bean id="shop2" class="com.q.spring.demo2.ShopDao2"> <property name="name" value="pear" /> <property name="price" value="22" /> </bean> <!-- 2. set 方法 (p名称空间属性注入) --> <bean id="shop2" class="com.q.spring.demo2.ShopDao2" p:name="q" p:price="2222"></bean> <!-- 2. set 方法 (SpEL 属性注入) --> <bean id="shop2" class="com.q.spring.demo2.ShopDao2"> <property name="name" value="#{'q1'}"></property> <property name="price" value="#{111}"></property> </bean>
// set 方式的属性注入(需要提供 set 方法) @Test public void demo2(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); ShopDao2 shopDao = (ShopDao2) applicationContext.getBean("shop2"); System.out.println(shopDao); }
3. set 方法注入对象类型 (属性中依赖类)
<!-- 3. set 方法注入对象类型的属性 --> <bean id="person" class="com.q.spring.demo2.Person"> <property name="name" value="q" /> <property name="shopDao2" ref="shop2" /> </bean> <!-- 3. set 方法注入对象类型的属性 (p名称空间属性注入) --> <bean id="person" class="com.q.spring.demo2.Person" p:name="q1" p:shopDao2-ref="shop2"></bean> <!-- 3. set 方法注入对象类型的属性 (SpEL 属性注入) --> <bean id="person" class="com.q.spring.demo2.Person"> <property name="name" value="#{'q1'}"></property> <property name="shopDao2" value="#{shop2}"></property> </bean>
// set 方法注入对象类型(需要提供 set 方法) @Test public void demo3(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Person person = (Person) applicationContext.getBean("person"); System.out.println(person); }
4. p名称空间属性注入
<bean id="person" class="com.q.spring.demo2.Person" p:name="q1" p:shopDao2-ref="shop2"></bean>
5. SpEL 属性注入 (Spring 3.0 之后)
<bean id="shop2" class="com.q.spring.demo2.ShopDao2"> <property name="name" value="#{'q1'}"></property> <property name="price" value="#{111}"></property> </bean>
6. 集合类型的注入 ( arrs list set map )
private String[] arrs; private List<String> list; private Set<String> set; private Map<String, String> map;
<bean id="typealls" class="com.q.spring.demo2.typeAlls"> <!-- 数组类型 --> <property name="arrs"> <list> <value>a</value> <value>b</value> <value>c</value> </list> </property> <!-- list集合 --> <property name="list"> <list> <value>a1</value> <value>b1</value> <value>c1</value> </list> </property> <!-- set集合 --> <property name="set"> <set> <value>a1</value> <value>b1</value> <value>c1</value> </set> </property> <!-- map 集合 --> <property name="map"> <map> <entry key="b2" value="b2" /> <entry key="b2" value="b2" /> <entry key="b2" value="b2" /> </map> </property> </bean>
五. 分模块开发的配置
1. 直接在一个xml文件中导入
<import resource="applicationContext.xml" />
2. 在创建 ClassPathXmlApplicationContext 时可传多个参数路径
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml1","applicationContext.xml2");
六. Spring 的 IOC 注解开发
1. 引入约束: 使用注解开发引入 Context 约束
<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" 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"> </beans>
2. 开启 Spring 的组件扫描
<!-- 配置组件扫描(哪些包下的类使用IOC注解) --> <context:component-scan base-package="包路径"></context:component-scan>
3. 在类上添加注解
- @Component : 组件
- 装饰一个类,将这个类交给 Spring 管理。
- 这个注解有三个衍生注解: - @Controller : web 层
- @Service : service 层
- @Repository : dao 层
import org.springframework.stereotype.Component; // value 可省略: @Component("shopDao") @Component(value = "userDao") // 相当于在 <bean id="userDao" class="com.q.spring.demo2.userDemo2" /> public class userDemo2 implements UserDao { public void save(){ } }
4. 注解方式设置属性值
注解方式:使用注解方式,可以没有 set 方法。
- 属性如果有 set 方法,需要将属性注入的注解加到 set 方法上。
// 如: @Value("添加注解") public void setName(String name){ this.name = name; }
- 属性如果没有 set 方法,需要将属性注入的注解添加到属性上。
// 如: @Value("添加注解") private String name;
5. 属性注入的注解
# 普通属性:
@Value : 设置普通属性的值
# 对象类型属性:
@Autowired : 设置对象类型的属性值。但是按照类型完成属性注入(按照类名的一致)。
- 可以通过 @Qualifier 和 @Autowired 配合使用来修改为按照名称属性注入。
@Resource : 完成对象类型的属性注入,按照名称完成属性注入。 (常用)。
6. Bean 的其他注解
# 生命周期相关注解:
@PostConstruct : 初始化方法
@PreDestroy : 销毁方法
# Bean 作用范围的注解:
@scope : 作用范围
参数:
- singleton : 默认单例
- prototype : 多例
七. Spring 的 AOP 的 XML 开发
1. applocationContext.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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置目标对象 :被增强的对象 --> <bean id="productDao" class="com.q.spring.demo1.ProductDaoImpl" /> <!-- 将切面类交给 Spring 管理 --> <bean id="myAspect" class="com.q.spring.demo1.MyAspectXml" /> <aop:config> <!-- 通过AOP的配置完成对目标类产生代理 --> <aop:pointcut expression="execution(* com.q.spring.demo1.ProductDaoImpl.save(..))" id="pointcut1" /> <aop:pointcut expression="execution(* com.q.spring.demo1.ProductDaoImpl.delete(..))" id="pointcut2" /> <aop:pointcut expression="execution(* com.q.spring.demo1.ProductDaoImpl.update(..))" id="pointcut3" /> <aop:pointcut expression="execution(* com.q.spring.demo1.ProductDaoImpl.find(..))" id="pointcut4" /> <!-- 配置切面 --> <aop:aspect ref="myAspect"> <!-- 前置通知:获得切入点信息 --> <aop:before method="checkPri" pointcut-ref="pointcut1" /> <!-- 后置通知 --> <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result" /> <!-- 环绕通知 --> <aop:around method="around" pointcut-ref="pointcut3" /> <!-- 异常抛出通知 --> <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex" /> <!-- 最终通知 --> <aop:after method="after" pointcut-ref="pointcut4" /> </aop:aspect> </aop:config> </beans>
2. ProductDao.java 接口文件
package com.q.spring.demo1; public interface ProductDao { public void save(); public void update(); public String delete(); public void find(); }
3. ProductDaoImpl.java DAO文件
package com.q.spring.demo1; public class ProductDaoImpl implements ProductDao { @Override public void save() { System.out.println("save"); } @Override public void update() { System.out.println("update"); } @Override public String delete() { System.out.println("delete"); return "Delete!!!"; } @Override public void find() { System.out.println("find"); // int i = 1/0; } }
4. MyAspectXML.java
package com.q.spring.demo1; // 切面类 import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class MyAspectXml { // 前置通知 public void checkPri(JoinPoint joinpoint){ System.out.println("权限校验 "+ joinpoint); } // 后置通知 public void writeLog(Object result){ System.out.println("日志记录 "+ result); } // 环绕通知 : 性能监控 public Object around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("环绕前通知..."); Object obj = joinPoint.proceed(); System.out.println("环绕后通知..."); return obj; } // 异常抛出通知 public void afterThrowing(Throwable ex){ System.out.println("异常抛出通知..."+ ex.getMessage()); } // 最终通知:类似于 finally public void after(){ System.out.println("最终通知..."); } }
5. 测试文件
package com.q.spring.demo1; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringDemo1 { @Resource(name="productDao") private ProductDao productDao; @Test public void demo1(){ productDao.save(); productDao.update(); productDao.delete(); productDao.find(); } }
八. Srping 的 AOP 注解
1. applocationContext.xml 文件
<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" 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"> <!-- 在配置文件中开启注解的AOP开发 --> <aop:aspectj-autoproxy /> <!-- 配置目标类 --> <bean id="orderDao" class="com.q.spring.demo1.OrderDao" /> <!-- 配置切面类 --> <bean id="myAspect" class="com.q.spring.demo1.MyAspectAnno" /> </beans>
2. OrderDao.java 文件
package com.q.spring.demo1; public class OrderDao { public void save(){ System.out.println("save..."); } public void update(){ System.out.println("update..."); } public String delete(){ System.out.println("delete..."); return "Delete!!!"; } public void find(){ System.out.println("find..."); // int i = 1/0; } }
3. MyAspectAnno.java 文件
package com.q.spring.demo1; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; @Aspect public class MyAspectAnno { // 前置通知 // execution(* com.q.spring.demo1.OrderDao.save(..)) @Before(value = "MyAspectAnno.pointcut1()") public void befor(){ System.out.println("前置增强"); } // 后置通知 @AfterReturning(value = "MyAspectAnno.pointcut3()", returning = "result") public void afterReturning(Object result){ System.out.println("后置增强 "+ result); } // 环绕通知 @Around(value = "MyAspectAnno.pointcut2()") 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.pointcut4()") public void afterThrowing(){ System.out.println("最终增强"); } // 切入点注解 @Pointcut(value = "execution(* com.q.spring.demo1.OrderDao.save(..))") private void pointcut1(){} @Pointcut(value = "execution(* com.q.spring.demo1.OrderDao.update(..))") private void pointcut2(){} @Pointcut(value = "execution(* com.q.spring.demo1.OrderDao.delete(..))") private void pointcut3(){} @Pointcut(value = "execution(* com.q.spring.demo1.OrderDao.find(..))") private void pointcut4(){} }
4. SpringDemo1.java 文件
package com.q.spring.demo1; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringDemo1 { @Resource(name = "orderDao") private OrderDao orderDao; @Test public void demo1(){ orderDao.save(); orderDao.update(); orderDao.delete(); orderDao.find(); } }
九. Spring 的 JDBC 模板
Spring 是一站式框架,有持久层解决方案
1. DBCP 连接池
# 文档..
2. C3P0 连接池
# 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" 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"> <!-- 配置C3P0连接池 --> <!-- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">--> <!-- <property name="driverClass" value="com.mysql.jdbc.Driver" />--> <!-- <property name="jdbcUrl" value="jdbc:mysql:///spring_jdbc" />--> <!-- <property name="user" value="root" />--> <!-- <property name="password" value="chaoqi" />--> <!-- </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 name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置 Spring 的JDBC的模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
# 增删改查操作
package com.q.jdbc.demo1; import com.q.jdbc.domain.Account; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class JdbcDemo2 { @Resource(name = "jdbcTemplate") private JdbcTemplate jdbcTemplate; // 增 @Test public void demo1(){ jdbcTemplate.update("insert into account values(null,?,?)","q4",152d); } // 改 @Test public void demo2(){ jdbcTemplate.update("update account set name=?, money = ? where id=? ","q1test",11d,2 ); } // 删 @Test public void demo3(){ jdbcTemplate.update("delete from account where id=? ",2); } // 查 @Test public void demo4(){ String name = jdbcTemplate.queryForObject("select name from account where id=?",String.class,3); 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(), 3); 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 res, int rowNum) throws SQLException { Account account = new Account(); account.setId(res.getInt("id")); account.setName(res.getString("name")); account.setMoney(res.getDouble("money")); return account; } } }
十. Spring 的事务传播行为
1. 报则保证多个操作在同一个事务中
PROPAGATION_REQUIRED : 默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来。
PROPAGATION_SUPPORTS : 支持事务
,如果A中有事务,使用A中的事务,如果没有,则不使用事务。
PROPAGATION_MANDATORY : 如果A中有事务,使用A中的事务,如果A中没有事务,则抛异常。
2. 保证多个操作不在同一个事务中
PROPAGATION_REQUIRES_NEW : 如果A中有事务,将A的事务挂起(暂停), 创建新事务,只包含自身操作。
如果A中没有事务,则创建一个新事务,包含自身操作
PROPAGATION_NOT_SUPPORTED : 如果A中有事务,将A的事务挂起,不使用事务管理。
PROPAGATION_NEVER : 如果A中有事务,则抛异常。
3. 嵌套式事务
PROPAGATION_NESTED : 嵌套事务,如果A中有事务,按照A的事务执行,执行完毕后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始的位置,也可以回滚到保存点。
十一. Spring 声明式事务管理一 (XML)
XML 步骤:
1. 引入 aop 开发包。
2. 配置事务管理器。
3. 配置增强<tx:Advice>
4. 配置aop
# 1. 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/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 配置 Service --> <bean id="accountService" class="com.q.tx.demo2.AccountServiceImpl"> <property name="accountDao" ref="accountDao" /> </bean> <!-- 配置 DAO --> <bean id="accountDao" class="com.q.tx.demo2.AccountDaoImpl"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置连接池的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 name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置事务管理 --> <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="*" propagation="REQUIRED" /> <!-- 实际开发中: --> <!-- <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:attributes> </tx:advice> <!-- AOP的配置 --> <aop:config> <aop:pointcut id="pointcut1" expression="execution(* com.q.tx.demo2.AccountServiceImpl.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1" /> </aop:config> </beans>
# jdbc.propertie.xml 文件属性设置
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_jdbc
jdbc.username=root
jdbc.password=chaoqi
# 2. AccountDaoImpl.java 文件
package com.q.tx.demo2; import org.springframework.jdbc.core.support.JdbcDaoSupport; // 转账Dao实现 public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override public void outMoney(Integer from, Double money) { this.getJdbcTemplate().update("update account set money = money - ? where id = ?", money, from); } @Override public void inMoney(Integer to, Double money) { this.getJdbcTemplate().update("update account set money = money + ? where id = ?", money, to); } }
# 3. AccountServiceImpl.java 文件
package com.q.tx.demo2; // 转账的业务层实现类 public class AccountServiceImpl implements AccountService { // 注入 DAO private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } /* from : 转出账号 to : 转人账号 money : 转账金额 */ @Override public void transfer(Integer from, Integer to, Double money) { accountDao.outMoney(from, money); // int i = 1/0; accountDao.inMoney(to, money); } }
# 4. 测试文件
package com.q.tx.demo2; // 测试类 import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:tx2.xml") public class SpringDemo1 { @Resource(name = "accountService") private AccountService accountService; @Test public void demo1(){ accountService.transfer(1,3,100d); } }
十二. Spring 声明式事务管理二 (注解方式)
注解 步骤:
1. 引入 aop 开发包。
2. 配置事务管理器。
3. 开启注解事务。
4. 在业务层添加注解
# 1. 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/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 配置 Service --> <bean id="accountService" class="com.q.tx.demo3.AccountServiceImpl"> <property name="accountDao" ref="accountDao" /> </bean> <!-- 配置 DAO --> <bean id="accountDao" class="com.q.tx.demo3.AccountDaoImpl"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置连接池的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 name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置事务管理器 第一步 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 开启注解事务 第二步 --> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
# 2. AccountDaoImpl 文件
package com.q.tx.demo3; import org.springframework.jdbc.core.support.JdbcDaoSupport; // 转账Dao实现 public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override public void outMoney(Integer from, Double money) { this.getJdbcTemplate().update("update account set money = money - ? where id = ?", money, from); } @Override public void inMoney(Integer to, Double money) { this.getJdbcTemplate().update("update account set money = money + ? where id = ?", money, to); } }
# 3. AccountServiceImpl 文件
package com.q.tx.demo3; import org.springframework.transaction.annotation.Transactional; // 转账的业务层实现类 // 第三步 需要在要进行事务操作的类上加 @Transactional @Transactional public class AccountServiceImpl implements AccountService { // 注入 DAO private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } /* from : 转出账号 to : 转人账号 money : 转账金额 */ @Override public void transfer(Integer from, Integer to, Double money) { accountDao.outMoney(from, money); // int i = 1/0; accountDao.inMoney(to, money); } }
# 4. 测试类
package com.q.tx.demo3; // 测试类 import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:tx3.xml") public class SpringDemo1 { @Resource(name = "accountService") private AccountService accountService; @Test public void demo1(){ accountService.transfer(1,3,100d); } }