一掏膏、@Aspectj注解配置切面編程
1.1. 搭建環(huán)境
1. Spring基本包(4+2: beans,context,core,expression + logging+log4j)
2. aop編程導(dǎo)入aop相關(guān)的包(2+2 : aop聯(lián)盟,aspectj,aop聯(lián)盟整合包,aspectj整合包)
3. Spring-Junit測(cè)試:test
--------------------------------------------------------------------------
4. 導(dǎo)入log4j.properties日志配置文件,導(dǎo)入含有beans,context,aop約束的applicationContext.xml
1.2. 使用注解完成aop編程
1. 確定目標(biāo)對(duì)象,注冊(cè)bean
2. 編寫(xiě)增強(qiáng)類(lèi),注冊(cè)bean
3. 使用注解配置切面和切入點(diǎn)
4. 測(cè)試
目標(biāo)對(duì)象:UserServiceImpl / ProductService
@Service("userService")
public class UserServiceImpl implements UserService {
@Override
// 使用Spring的AOP編程增強(qiáng)
public void save() {
System.out.println("用戶(hù)注冊(cè).........");
}
}
//沒(méi)有接口的目標(biāo)對(duì)象bean
@Service
public class ProductService {
//模擬添加商品..對(duì)該方法進(jìn)行增強(qiáng)
public void save() {
System.out.println("ProductService.......添加商品...........");
}
}
并在兩個(gè)目標(biāo)對(duì)象上使用@Service完成了bean的注解
---------------------------------------------------------------------------
編寫(xiě)增強(qiáng)類(lèi),注冊(cè)bean(MyAspect):
//通知/增強(qiáng)類(lèi),對(duì)切入點(diǎn)進(jìn)行增強(qiáng)
@Component //注冊(cè)bean,將增強(qiáng)類(lèi)交給Spring管理
@Aspect //將該類(lèi)標(biāo)識(shí)為切面類(lèi)(該類(lèi)里面有增強(qiáng)方法),相當(dāng)于<aop:aspect ref="myAspect">
public class MyAspect {
//前置增強(qiáng),參數(shù)value:寫(xiě)切入點(diǎn)表達(dá)式
//相當(dāng)于<aop:befoe method="writeLog" pointcut="bean(*Service)">
@Before("bean(*Service)")
public void writeLog() {
System.out.println("開(kāi)始寫(xiě)日志了......Spring..aop開(kāi)發(fā)");
}
}
-----------------------------------------------------------------------------
到這里,目標(biāo)bean的定義,增強(qiáng)類(lèi)的定義以及切面的配置完成,但是還需要在核心配置文件中開(kāi)啟注解掃描與自動(dòng)代理機(jī)制。
<?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">
<!-- 開(kāi)啟注解掃描組件 -->
<context:component-scan base-package="com.itdream.spring.aopanno"/>
<!-- 開(kāi)啟AspectJ注解自動(dòng)代理機(jī)制:
作用:能自動(dòng)掃描帶有@Aspect注解的bean,將其作為aop增強(qiáng)配置,有點(diǎn)類(lèi)似于aop-config
-->
<aop:aspectj-autoproxy/>
</beans>
-----------------------------------------------------------------------------
測(cè)試:
@RunWith(SpringJUnit4ClassRunner.class)//Spring整合Junit
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringTest {
//注入測(cè)試bean
@Autowired
@Qualifier("userService")
private UserService userService;
@Autowired
private ProductService productService;
@Test
public void test() {
userService.save();
System.out.println("======================");
productService.save();
}
}
補(bǔ)充:
我們的aop代理是使用的Spring的內(nèi)部代理機(jī)制惑芭,默認(rèn)是如果有接口就優(yōu)先對(duì)接口代理(jdk動(dòng)態(tài)代理)抛腕。
問(wèn)題:如果目標(biāo)對(duì)象有接口蠢笋,能否只對(duì)實(shí)現(xiàn)類(lèi)代理藻三,而不對(duì)接口進(jìn)行代理?可以颠区!
這里要使用子類(lèi)的擴(kuò)展方法,而接口中沒(méi)有該方法,因?yàn)榇韺?duì)象與目標(biāo)對(duì)象不能互轉(zhuǎn),所以不能調(diào)用通铲。
這時(shí)可以使用類(lèi)代理(cglib動(dòng)態(tài)代理)毕莱,只需要設(shè)置 proxy-target-class = true
1.3. 使用@Pointcut 定義切入點(diǎn)
問(wèn)題:如果直接在通知注解中寫(xiě)切入點(diǎn)表達(dá)式,會(huì)發(fā)生重復(fù)編寫(xiě)颅夺,后期不便于維護(hù)
解決:
在實(shí)際開(kāi)發(fā)中朋截,切入點(diǎn)都是單獨(dú)定義維護(hù)的,如:
* 使用xml定義切入點(diǎn)<aop:pointcut>
* 使用注解單獨(dú)定義切入點(diǎn)@Pointcut
語(yǔ)法要求:
切點(diǎn)方法:private void 無(wú)參數(shù)方法吧黄,方法名為切點(diǎn)名
=============================================================================
//通知/增強(qiáng)類(lèi),對(duì)切入點(diǎn)進(jìn)行增強(qiáng)
@Component
@Aspect
public class MyAspect {
// 定義切入點(diǎn),id/name就是方法名
// 優(yōu)點(diǎn):方便統(tǒng)一維護(hù)
@Pointcut("bean(*Service)") // 定義切入點(diǎn)表達(dá)式
private void myPointcut() {
}
// @Before("bean(*Service)")
// 建立切入點(diǎn)與通知之前的關(guān)聯(lián),完整類(lèi)名.方法名
// @Before("com.itdream.spring.aopanno.MyAspect.myPointcut()")
@Before("myPointcut()") // 因?yàn)樵陬?lèi)的內(nèi)部,可簡(jiǎn)寫(xiě)
public void writeLog() {
System.out.println("開(kāi)始寫(xiě)日志了......Spring..aop開(kāi)發(fā)");
}
}
測(cè)試結(jié)果:
另外部服,一個(gè)通知方法也可以對(duì)多個(gè)切入點(diǎn)進(jìn)行增強(qiáng):
二、Spring JdbcTemplate模板類(lèi)
2.1 概述
Spring中有一系列XxxTemplate類(lèi)稚字,這些類(lèi)主要是用于簡(jiǎn)化xxx的編程饲宿。
Spring JdbcTemplate 是一個(gè)模板工具類(lèi)厦酬,簡(jiǎn)化Jdbc編程 (類(lèi)似 Apache DbUtils )
JdbcTemplate 簡(jiǎn)化 jdbc編程
HibernateTemplate 極大的簡(jiǎn)化 Hibernate編程
2.2 JdbcTemplate快速入門(mén)-代碼
目標(biāo):使用Jdbc Template操作數(shù)據(jù)庫(kù)胆描。
1. 搭建環(huán)境
1. 4+2個(gè)Spring基本jar包:beans,core,context,expression+logging,log4j.
2. 導(dǎo)入JDBC模板開(kāi)發(fā)包(2個(gè)):spring-jdbc.jar , spring-tx.jar ,有耦合性,因此操作jdbc需要導(dǎo)入tx,操作事務(wù)需要導(dǎo)入jdbc
3. 導(dǎo)入測(cè)試包:spring-test.jar
4. 數(shù)據(jù)庫(kù)驅(qū)動(dòng)
5. 導(dǎo)入log4j.properties配置文件和核心配置文件applicationContext.xml
2. 代碼
1. 編寫(xiě)Service層仗阅、dao層操作數(shù)據(jù)庫(kù)
===========================================================================
dao層:
public class UserDAO {
//使用jdbc Template模板類(lèi)操作數(shù)據(jù)庫(kù)
public void create() {
//創(chuàng)建數(shù)據(jù)源(連接數(shù)據(jù)庫(kù))昌讲,內(nèi)置連接池,不建議生產(chǎn)環(huán)境下使用
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring");
dataSource.setUsername("root");
dataSource.setPassword("root");
//創(chuàng)建JdbcTemplate模板對(duì)象,簡(jiǎn)化JDBC代碼
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//設(shè)置數(shù)據(jù)源(連接池)
jdbcTemplate.setDataSource(dataSource);
jdbcTemplate.execute("create table user001 (name varchar(20))");
}
}
service層:
public class UserService {
//業(yè)務(wù)層,調(diào)用dao層
public void create() {
UserDAO userDAO = new UserDAO();
userDAO.create();
}
}
以上是使用JdbcTemplate操作數(shù)據(jù)庫(kù)的基本方式。
2.3. JdbcTemplate的XML配置方式
目標(biāo):將數(shù)據(jù)源和jdbcTemplate都交給Spring來(lái)管理减噪。
這里還是使用Spring的內(nèi)置的連接池短绸。
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置Spring內(nèi)置數(shù)據(jù)源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/spring" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- 注冊(cè)JdbcTemplate模板類(lèi) -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 注冊(cè)UserDAO對(duì)象 -->
<bean id="userDAO" class="com.itdream.dao.UserDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!-- 注冊(cè)UserService -->
<bean id="userService" class="com.itdream.service.UserService">
<property name="userDAO" ref="userDAO"/>
</bean>
</beans>
注意:
UserDAO中提供JdbcTemplate的聲明以及setter方法,以供屬性注入车吹。
UserService中提供UserDAO的聲明以及setter方法,以供UserDAO注入。
測(cè)試:
@RunWith(SpringJUnit4ClassRunner.class)//整合Spring與Junit
@ContextConfiguration(locations="classpath:applicationContext.xml")//為Spring容器指定配置文件
public class SpringTest {
@Autowired
private UserService userService;
@Test
public void test() {
userService.create();
System.out.println("建表成功");
}
}
2.4 使用JdbcDaoSupport簡(jiǎn)化開(kāi)發(fā)
上面我們使用xml配置,將數(shù)據(jù)源,模板類(lèi),UserDAO以及UserService交給了Spring管理,但是配置文件中寫(xiě)的代碼有點(diǎn)多醋闭。
Spring提供了JdbcDaoSupport來(lái)方便Dao中注入Jdbc Template.
我們只需要繼承JdbcDaoSupport窄驹,將這個(gè)dao類(lèi)注冊(cè)成bean,注入dataSource數(shù)據(jù)源即可。
它會(huì)調(diào)用父類(lèi)JdbcDaoSupport的setDataSource方法,將注入的DataSource傳入证逻,返回一個(gè)JdbcTemplate
因此,我們?cè)赿ao類(lèi)中,直接獲取父類(lèi)配置了注入數(shù)據(jù)源的JdbcTemplate使用即可
============================================================================
userDAO:(之前定義用于注入的JdbcTemplate代碼就節(jié)省了)
public class UserDAO extends JdbcDaoSupport {
// Spring注入的DataSource會(huì)調(diào)用父類(lèi)JdbcDaoSupport中的setDataSource方法
// 該方法會(huì)return new JdbcTemplate(dataSource);這個(gè)dataSource就是配置文件中注入的dataSource\
// 因此父類(lèi)中就有了一個(gè)配置了注入數(shù)據(jù)源的JdbcTemplate,我們直接get父類(lèi)的JdbcTemplate模板類(lèi)使用即可
// 使用jdbc Template模板類(lèi)操作數(shù)據(jù)庫(kù)
public void create() {
getJdbcTemplate().execute("create table user002 (name varchar(20))");
}
}
UserService:
public class UserService {
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
// 業(yè)務(wù)層,調(diào)用dao層
public void create() {
userDAO.create();
}
}
--------------------------------------------------------------------------
配置文件applicationContext.xml:(不需要注冊(cè)JdbcTemplate,直接向DAO中注入數(shù)據(jù)源dataSource即可)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置Spring內(nèi)置數(shù)據(jù)源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/spring" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- 注冊(cè)UserDAO對(duì)象 -->
<bean id="userDAO" class="com.itdream.dao.UserDAO">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注冊(cè)UserService -->
<bean id="userService" class="com.itdream.service.UserService">
<property name="userDAO" ref="userDAO"/>
</bean>
</beans>
測(cè)試:
2.4 配置自定義連接池
2.4.1 DBCP連接池的配置
1.導(dǎo)入DBCP連接池所需的jar包(tomcat內(nèi)置了apache dbcp的jar包)
commons-pool-1.5.6.jar commons-dbcp-1.4.jar
2. 配置DBCP連接池(根據(jù)setter方法確定name)
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/spring" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
DBCP連接池的配置與Spring內(nèi)置連接池的配置幾乎一模一樣,修改一下class即可乐埠。
2.4.2 C3P0連接池的配置
1.導(dǎo)入C3P0連接池所需的jar包
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
2. 配置DBCP連接池(根據(jù)setter方法確定name)
<!-- 配置C3P0數(shù)據(jù)源(連接池) -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring" />
<property name="user" value="root" />
<property name="password" value="root" />
</bean>
2.5. 外部屬性文件的引入配置
上面我們進(jìn)行了數(shù)據(jù)源(連接池)在Spring中的配置,我們有時(shí)候需要更換連接池,而配置文件的代碼很多,修改起來(lái)不方便,因此將它的參數(shù)提取出來(lái)放在一個(gè)配置文件中。
模擬需求:
現(xiàn)在數(shù)據(jù)源的相關(guān)參數(shù)配置囚企,是測(cè)試環(huán)境下的丈咐。
現(xiàn)在,要將工程搭建在正式的服務(wù)器上龙宏,因?yàn)闇y(cè)試環(huán)境和正式環(huán)境的數(shù)據(jù)庫(kù)肯定不是一個(gè)棵逊。
所以肯定首先要更改數(shù)據(jù)源相關(guān)的配置奈籽。將數(shù)據(jù)源相關(guān)配置參數(shù)兵睛,外置。
目的:可以將xml配置中可能要經(jīng)常修改內(nèi)容后添,抽取到一個(gè)properties文件
應(yīng)用:使用properties文件配置參數(shù)黍特,如數(shù)據(jù)庫(kù)連接參數(shù)等秸歧。
------------------------------------------------------------------------------
1. 從applicationContext.xml中抽取經(jīng)常修改的變量
例如:
jdbc.dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root
2. 在applicationContext.xml中讀取抽取出去的變量
首先要使用context:property-placeholder標(biāo)簽引入外界配置文件。
1. 因此首先要導(dǎo)入,context有關(guān)的schema約束衅澈。
2. 引入外界配置文件設(shè)置
3. 引入變量
<!--引入頭約束 -->
<?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"
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">
<!-- 引入外部配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置C3P0數(shù)據(jù)源(連接池) -->
<bean id="dataSource" class="${jdbc.dataSource}">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.jdbcUrl}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
............................
</beans>
2.6. 使用Jdbc Template進(jìn)行CRUD操作
ProductDAO :
//使用JDBC Template進(jìn)行CRUD操作
public class ProductDAO extends JdbcDaoSupport {
// 繼承了JdbcDaoSupport類(lèi),不需注入JdbcTemplate,只需要注入DataSource連接池即可
// DAO中注入連接池DataSource,Spring會(huì)找到父類(lèi)中的setDataSource,從而創(chuàng)建一個(gè)配置了注入連接池的JdbcTemplate
// 因此在這里,我們可以直接調(diào)用父類(lèi)的getJdbcTemplate()方法即可
// 增加商品
public void save(Product product) {
String sql = "insert into product values(null,?,?)";
getJdbcTemplate().update(sql, product.getPname(), product.getPrice());
}
// 刪除商品
public void delete(Product product) {
String sql = "delete from product where pid=?";
getJdbcTemplate().update(sql, product.getPid());
}
// 修改商品
public void update(Product product) {
String sql = "update product set price=? where pid=?";
getJdbcTemplate().update(sql, product.getPrice(), product.getPid());
}
// 投影查詢(xún)
public Object findNameById(int pid) {
String sql = "select pname from product where pid=?";
return getJdbcTemplate().queryForObject(sql, new SingleColumnRowMapper<>(), pid);
}
// 投影查詢(xún)
public Object findColumnsById(int pid) {
String sql = "select pname,price from product where pid=?";
return getJdbcTemplate().queryForObject(sql, new ColumnMapRowMapper(), pid);
}
// 查詢(xún)單個(gè)商品
public Product query(int pid) {
String sql = "select * from product where pid=?";
return getJdbcTemplate().queryForObject(sql, new BeanPropertyRowMapper<>(Product.class), pid);
}
// 查詢(xún)多商品
public List<Product> queryProducts(String pname) {
String sql = "select * from product where pname like ?";
return getJdbcTemplate().query(sql, new BeanPropertyRowMapper(Product.class), "%" + pname + "%");
}
//查詢(xún)所有商品
public List<Product> findAll() {
String sql = "select * from product";
return getJdbcTemplate().query(sql, new BeanPropertyRowMapper(Product.class));
}
}
---------------------------------------------------------------------------
配置文件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"
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">
<!-- 引入外部配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置C3P0數(shù)據(jù)源(連接池) -->
<bean id="dataSource" class="${jdbc.dataSource}">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.jdbcUrl}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 注冊(cè)productDAO對(duì)象 -->
<bean id="productDAO" class="com.itdream.dao.ProductDAO">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 注冊(cè)Product的bean對(duì)象 -->
<bean id="product" class="com.itdream.domain.Product">
<property name="pid" value="1"/>
<property name="pname" value="Iphone"/>
<property name="price" value="6999D"/>
</bean>
</beans>
---------------------------------------------------------------------------
測(cè)試:
@RunWith(SpringJUnit4ClassRunner.class) // 整合Spring,否則不能注入測(cè)試bean
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpringTest {
@Autowired
private ProductDAO productDAO;
@Autowired
private Product product;
@Test
public void test() {
// productDAO.save(product);
// productDAO.delete(product);
// product.setPid(2);
// product.setPrice(2999D);
// productDAO.update(product);
System.out.println(productDAO.findNameById(2));
System.out.println(productDAO.findColumnsById(2));
System.out.println(productDAO.query(2));
System.out.println(productDAO.queryProducts("one"));
System.out.println(productDAO.findAll());
}
}
=============================================================================
總結(jié):
- 增刪改的操作使用update
- 簡(jiǎn)單查詢(xún)使用```queryForObject````查詢(xún)
- 封裝單個(gè)對(duì)象使用
BeanPropertyRowMapper
封裝 - 投影查詢(xún)對(duì)象屬性使用
ColumnMapRowMapper
- 封裝單個(gè)對(duì)象使用
- 復(fù)雜的查詢(xún)使用
query
查詢(xún)- 封裝使用
new BeanPropertyRowMapper
封裝
- 封裝使用
三键菱、 Spring的事務(wù)管理機(jī)制【了解】
Spring事務(wù)管理高層抽象主要包括3個(gè)接口,Spring的事務(wù)主要是由他們共同完成的:
- PlatformTransactionManager:事務(wù)管理器—主要用于平臺(tái)相關(guān)事務(wù)的管理
- TransactionDefinition: 事務(wù)定義信息(隔離今布、傳播经备、超時(shí)、只讀)—通過(guò)配置如何進(jìn)行事務(wù)管理部默。
- TransactionStatus:事務(wù)具體運(yùn)行狀態(tài)—事務(wù)管理過(guò)程中侵蒙,每個(gè)時(shí)間點(diǎn)事務(wù)的狀態(tài)信息。
3.1. PlatformTransactionManager事務(wù)管理器
該接口提供三個(gè)方法:
- commit : 提交事務(wù)
- rollback : 回滾事務(wù)
- getTransaction : 獲取事務(wù)狀態(tài)
Spring為不同的持久化框架提供了不同PlatformTransactionManager接口實(shí)現(xiàn):
-
DataSourceTransactionManager
針對(duì)JdbcTemplate傅蹂、MyBatis
事務(wù)控制 纷闺,使用Connection
(連接)進(jìn)行事務(wù)控制 :-
connection.setAutoCommit(false)
:開(kāi)啟事務(wù) -
connection.rollback()
:回滾事物 -
connection.commit()
:提交事物
-
-
HibernateTransactionManager
針對(duì)Hibernate
框架進(jìn)行事務(wù)管理, 使用Session的Transaction
相關(guān)操作進(jìn)行事務(wù)控制 :-
session.beginTransaction()
:開(kāi)啟事務(wù) -
session.getTransaction.commit
:提交事務(wù) -
session.getTransaction.rollback
:回滾事務(wù)
-
根據(jù)選擇和使用的持久層技術(shù)份蝴,來(lái)選擇對(duì)應(yīng)的事務(wù)管理器犁功。
3.2. TransactionDefinition事務(wù)定義信息
該接口主要提供的方法:
-
getIsolationLevel
:隔離級(jí)別獲取 -
getPropagationBehavior
:傳播行為獲取 -
getTimeout
:獲取超時(shí)時(shí)間(事務(wù)的有效期) -
isReadOnly
: 是否只讀。事務(wù)管理器能夠根據(jù)這個(gè)返回值進(jìn)行優(yōu)化婚夫。- 保存浸卦、更新、刪除—對(duì)數(shù)據(jù)進(jìn)行操作-設(shè)置為false(默認(rèn)值),變成可讀寫(xiě)的案糙,
- 查詢(xún)-設(shè)置這個(gè)屬性為true限嫌,只能讀不能寫(xiě))
這些事務(wù)的定義信息靴庆,都可以在配置文件中配置和定制。
3.2.1. IsolationLevel事務(wù)的隔離級(jí)別
Spring使用默認(rèn)的defalut:根據(jù)數(shù)據(jù)庫(kù)的默認(rèn)隔離級(jí)別確定
* MySQL的默認(rèn)隔離級(jí)別是Repeatable_Read,可重復(fù)讀
* Oracle的默認(rèn)隔離級(jí)別是Read_Commit,讀已提交
3.2.2. 事務(wù)的傳播行為Transaction Propagation Behavior
事務(wù)傳播行為用于解決兩個(gè)被事務(wù)管理的方法互相調(diào)用問(wèn)題
業(yè)務(wù)層兩個(gè)方法面臨的事務(wù)問(wèn)題:有些時(shí)候需要處于同一個(gè)事務(wù)怒医,有些時(shí)候不能在同一個(gè)事務(wù) 炉抒!
事務(wù)的傳播行為的7種類(lèi)型:
有關(guān)事務(wù)傳播行為的詳細(xì)解釋?zhuān)?/strong>
PROPAGATION_REQUIRED(默認(rèn)值)
A中有事務(wù),使用A中的事務(wù).如果A中沒(méi)有,B就會(huì)開(kāi)啟一個(gè)新的事務(wù),將A包含進(jìn)來(lái).(保證A,B在同一個(gè)事務(wù)中)稚叹,默認(rèn)值6死瘛!
?PROPAGATION_SUPPORTS
A中有事務(wù),使用A中的事務(wù).如果A中沒(méi)有事務(wù).那么B也不使用事務(wù).
?PROPAGATION_MANDATORY
A中有事務(wù),使用A中的事務(wù).如果A沒(méi)有事務(wù).拋出異常.
?PROPAGATION_REQUIRES_NEW
A中有事務(wù),將A中的事務(wù)掛起.B創(chuàng)建一個(gè)新的事務(wù).(保證A,B沒(méi)有在一個(gè)事務(wù)中)
?PROPAGATION_NOT_SUPPORTED
A中有事務(wù),將A中的事務(wù)掛起.
?PROPAGATION_NEVER
A中有事務(wù),拋出異常.
?PROPAGATION_NESTED
嵌套事務(wù).當(dāng)A執(zhí)行之后,就會(huì)在這個(gè)位置設(shè)置一個(gè)保存點(diǎn).如果B沒(méi)有問(wèn)題.執(zhí)行通過(guò).如果B出現(xiàn)異常,運(yùn)行客戶(hù)根據(jù)需求回滾
為方便記憶入录,將Spring的事務(wù)傳播行為分為三大類(lèi):
**PROPAGATION_REQUIRED(默認(rèn)值)**蛤奥、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY
支持當(dāng)前事務(wù)僚稿, A調(diào)用B凡桥,如果A事務(wù)存在,B和A處于同一個(gè)事務(wù) 蚀同。
事務(wù)默認(rèn)傳播行為 REQUIRED缅刽。最常用的。
**PROPAGATION_REQUIRES_NEW**蠢络、PROPAGATION_NOT_SUPPORTED衰猛、PROPAGATION_NEVER
不會(huì)支持原來(lái)的事務(wù) ,A調(diào)用B刹孔, 如果A事務(wù)存在啡省, B肯定不會(huì)和A處于同一個(gè)事務(wù)。
常用的事務(wù)傳播行為:PROPAGATION_REQUIRES_NEW
**PROPAGATION_NESTED**
嵌套事務(wù) 髓霞,只對(duì)DataSourceTransactionManager有效 卦睹,底層使用JDBC的SavePoint機(jī)制,允許在同一個(gè)事務(wù)設(shè)置保存點(diǎn)方库,回滾保存點(diǎn)
面試題: REQUIRED结序、REQUIRES_NEW、NESTED 區(qū)分纵潦?
REQUIRED 一個(gè)事務(wù)(默認(rèn)徐鹤,推薦)
REQUIRES_NEW 兩個(gè)事務(wù)
NESTED 一個(gè)事務(wù),事務(wù)可以設(shè)置保存點(diǎn)邀层,回滾到保存點(diǎn) 返敬,選擇提交或者回滾
3.3. TransactionStatus 事務(wù)狀態(tài)
-
flush(),給hibernate
使用被济,底層發(fā)出sql的 -
hasSavepoint()
:判斷是否有保留點(diǎn) -
isCompleted()
:判斷事務(wù)是否結(jié)束 -
isNewTransaction()
:判斷當(dāng)前事務(wù)是否是新開(kāi)的一個(gè)事務(wù)救赐。 -
isRollbackOnly()
:判斷事務(wù)是否只能回滾 -
setRollbackOnly()
:設(shè)置事務(wù)是否回滾
數(shù)據(jù)庫(kù)操作中涧团,如果只是回滾只磷,后面不操作经磅,數(shù)據(jù)庫(kù)在關(guān)閉連接的時(shí)候,自動(dòng)發(fā)出了commit钮追。commit結(jié)束事務(wù)预厌。
三個(gè)事務(wù)超級(jí)接口對(duì)象之間的關(guān)系:
- 用戶(hù)管理事務(wù),需要先配置
TransactionDefinition
(事務(wù)定義信息元媚、事務(wù)的管理方案)轧叽; - 然后根據(jù)
TransactionDefinition
,通過(guò)TransactionManager
(事務(wù)管理器)進(jìn)行事務(wù)管理刊棕; - 事務(wù)運(yùn)行過(guò)程中炭晒,每個(gè)時(shí)刻都可以通過(guò)獲取
TransactionStatus
(事務(wù)狀態(tài))來(lái)了解事務(wù)的運(yùn)行狀態(tài)。
3.4. Spring事務(wù)管理兩種方式
- 編程式的事務(wù)管理(有侵入性,很少用)
-
使用XML或注解配置聲明式事務(wù)【開(kāi)發(fā)中使用】
- Spring的聲明事務(wù)通過(guò)AOP實(shí)現(xiàn)(環(huán)繞通知)
3.4.1 使用XML配置聲明式事務(wù)
示例:
需求:
銀行轉(zhuǎn)賬:轉(zhuǎn)出甥角、轉(zhuǎn)入,使用Spring的聲明式事務(wù)
-------------------------------------------------------------------------
步驟:
1. 搭建環(huán)境
1. 導(dǎo)入jar包
Spring基本包:4+2 : beans,context,core,expression. + apache logging,log4j
spring測(cè)試包: test
spring事務(wù)包: tx,jdbc(jdbc與tx有耦合,使用其中一個(gè)包必須導(dǎo)入另一個(gè))
spring的事務(wù)依賴(lài)AOP(2+2):apache-aop聯(lián)盟网严,aspect. spring對(duì)兩個(gè)包的整合包
數(shù)據(jù)庫(kù)驅(qū)動(dòng):mysql-converter
c3p0連接池的jar包
--------------------------------------------------------------------
2. 導(dǎo)入log4j.properties配置文件,applicationContext.xml配置文件
3. 完成數(shù)據(jù)庫(kù)建表以及模擬的兩個(gè)用戶(hù)
4. 根據(jù)表編寫(xiě)實(shí)體類(lèi)User
2. 完成功能
1. 編寫(xiě)UserDAO的轉(zhuǎn)入轉(zhuǎn)出數(shù)據(jù)庫(kù)操作(使用JdbcTemplate)
2. 編寫(xiě)UserService完成業(yè)務(wù)邏輯操作
3. 完成事務(wù)增強(qiáng)
1. 確定目標(biāo)類(lèi),注冊(cè)bean
2. 注冊(cè)增強(qiáng)類(lèi)
3. 配置切面和切入點(diǎn)(切入點(diǎn)和通知之間的關(guān)聯(lián))
3. 測(cè)試
===========================================================================
1. 搭建環(huán)境:
jar包:
創(chuàng)建數(shù)據(jù)庫(kù)表user:
CREATE DATABASE spring;
CREATE TABLE USER(
uid INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20),
acount DOUBLE
);
INSERT INTO USER VALUES(NULL,'tom',1000),(NULL,'jack',1000);
創(chuàng)建實(shí)體類(lèi)User:
//User的實(shí)體類(lèi)
public class User {
private Integer uid;
private String username;
private Double acount;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Double getAcount() {
return acount;
}
public void setAcount(Double acount) {
this.acount = acount;
}
@Override
public String toString() {
return "User [uid=" + uid + ", username=" + username + ", acount=" + acount + "]";
}
}
導(dǎo)入log4j.properties,applicationContext.xml核心配置文件。
2. 業(yè)務(wù)實(shí)現(xiàn):
UserDAO:
//模擬銀行轉(zhuǎn)賬
public class UserDAO extends JdbcDaoSupport {
// 注入dataSource父類(lèi)會(huì)自動(dòng)創(chuàng)建一個(gè)配置了注入數(shù)據(jù)源的JdbcTemplate
// 轉(zhuǎn)出
public void out(String outname, Double money) {
String sql = "update user set acount=acount-? where username=?";
getJdbcTemplate().update(sql, money, outname);
}
// 轉(zhuǎn)入
public void in(String inname, Double money) {
String sql = "update user set acount=acount+? where username=?";
getJdbcTemplate().update(sql, money, inname);
}
}
UserService:
public class UserService {
// 注入userDAO
private UserDAO userDAO;
// 提供setter方法
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
public void transfer(String outname, String inname, Double money) {
//開(kāi)啟事務(wù)
//轉(zhuǎn)出
userDAO.out(outname, money);
//制造異常
//int i = 1/0;
//轉(zhuǎn)入
userDAO.in(inname, money);
//關(guān)閉事務(wù)
}
}
---------------------------------------------------------------------------
配置applicationContext.xml完成Spring的聲明式事務(wù):
頭約束:
因?yàn)镴dbcTemplate和事務(wù)管理器都需要導(dǎo)入數(shù)據(jù)源,因此配置了c3p0連接池,抽取了變量另外配置嗤无。
為了能引入外部配置,使用context..placeholder,需要引入context頭約束震束。
因?yàn)橐褂檬聞?wù),因此需要導(dǎo)入aop和tx的頭約束(spring的事務(wù)依賴(lài)aop的環(huán)繞通知完成)
外部數(shù)據(jù)源的配置(db.properties):
jdbc.dataSourceClass=com.mchange.v2.c3p0.ComboPooledDataSource
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root
核心配置文件(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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 引入外部配置文件(首先引入Context頭約束) -->
<context:property-placeholder location="db.properties"/>
<!-- 配置C3P0數(shù)據(jù)源,使用${key}引入外部配置文件中的變量 -->
<bean id="dataSource" class="${jdbc.dataSourceClass}">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 注冊(cè)UserDAO -->
<bean id="userDAO" class="com.itdream.dao.UserDAO">
<!-- 注入數(shù)據(jù)源,獲取配置了注入數(shù)據(jù)源的JdbcTemplate對(duì)象 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注冊(cè)UserService,也是目標(biāo)bean -->
<bean id="userService" class="com.itdream.service.UserService">
<property name="userDAO" ref="userDAO"/>
</bean>
<!-- Spring的事務(wù)管理 -->
<!-- 配置一個(gè)事務(wù)管理器,給通知advice進(jìn)行注入使用 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 因?yàn)椴煌某志脤?需要開(kāi)啟事務(wù)的連接不同,因此需要注入數(shù)據(jù)源(連接池)
事實(shí)上,DataSourceTransactionManager中有setDataSource()方法供注入
-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 增強(qiáng)bean -->
<!-- Spring提供的事務(wù)增強(qiáng)通知類(lèi),Spring為了簡(jiǎn)化配置,我們只需要使用tx:advice標(biāo)簽就相當(dāng)于將該增強(qiáng)類(lèi)注冊(cè)了当犯。
tx:advice等價(jià)于<bean id="txAdvcie" class="....MethodInterceptor..">
-->
<!-- trasaction-manager相當(dāng)于:<property name=""
-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 配置Spring的事務(wù)屬性 -->
<tx:attributes>
<!-- 對(duì)指定方法設(shè)置事務(wù)屬性
isolation:事務(wù)的隔離級(jí)別,不寫(xiě),默認(rèn)default,根據(jù)數(shù)據(jù)庫(kù)的默認(rèn)隔離級(jí)別
timeout:超時(shí)時(shí)間,默認(rèn)-1,根據(jù)數(shù)據(jù)庫(kù)的默認(rèn)超時(shí)時(shí)間
propagation:事務(wù)傳播狀態(tài),默認(rèn)required,一個(gè)事務(wù),一般不改
read-only:是否只讀,默認(rèn)false,可讀寫(xiě).增刪改數(shù)據(jù)庫(kù)時(shí)使用默認(rèn),查詢(xún)時(shí)使用true
no-rollback-for:遇到什么異常不回滾,其他的都會(huì)滾
rollback-for:遇到什么異常就回滾,剩下的不回滾
一般就設(shè)置一下read-only
-->
<tx:method name="transfer"
isolation="DEFAULT" timeout="-1"
propagation="REQUIRED" read-only="false"
no-rollback-for="" rollback-for=""
/>
</tx:attributes>
</tx:advice>
<!-- 配置切入點(diǎn)與切面,建立切入點(diǎn)與通知的關(guān)聯(lián) -->
<aop:config>
<!-- 定義切入點(diǎn),即哪些方法需要被事務(wù)增強(qiáng)器進(jìn)行增強(qiáng) -->
<aop:pointcut expression="execution(* com.itdream.service.UserService.transfer(..))" id="myPointcut"/>
<!-- 定義切面,這里使用的舊的aop,不是新的aspectJ的aop
只支持一對(duì)一的切入點(diǎn)與通知的關(guān)聯(lián)
-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
</aop:config>
</beans>
---------------------------------------------------------------------------
測(cè)試:
@RunWith(SpringJUnit4ClassRunner.class)//整合Spring進(jìn)行測(cè)試
@ContextConfiguration(locations="classpath:applicationContext.xml")//為Spring容器指定配置文件
public class SpringTest {
@Autowired
//注入測(cè)試bean
private UserService userService;
@Test
public void testTransfer() {
//tom向jack轉(zhuǎn)賬1000元
userService.transfer("tom", "jack", 100D);
System.out.println("轉(zhuǎn)賬成功.............");
}
}
3.4.2 使用注解配置聲明式事務(wù)
步驟:
1. 確定目標(biāo)類(lèi)垢村,方法(要被增強(qiáng)的方法,即切入點(diǎn)),注冊(cè)bean
2. 確定增強(qiáng)類(lèi)(這里要完成事務(wù)管理),Spring已經(jīng)幫我們實(shí)現(xiàn)了
3. 配置切面關(guān)系(注解實(shí)現(xiàn))嚎卫,在需要管理事務(wù)的方法或者類(lèi)上面 添加@Transactional 注解
4. 配置注解驅(qū)動(dòng)事務(wù)管理(事務(wù)管理注解生效的作用)(需要配置對(duì)特定持久層框架使用的事務(wù)管理器)
-----------------------------------------------------------------------------
1. @Service將目標(biāo)類(lèi) UserService注冊(cè)成bean
2. Spring已經(jīng)幫我們實(shí)現(xiàn)了事務(wù)管理的增強(qiáng)類(lèi),無(wú)需手動(dòng)實(shí)現(xiàn)并注冊(cè)了
3. 配置切面關(guān)系,@Transactional寫(xiě)在需要增強(qiáng)的方法或類(lèi)上
@Service("userService")
public class UserService {
// 注入userDAO
@Autowired
@Qualifier("userDAO")
private UserDAO userDAO;
//在需要管理事務(wù)的方法或類(lèi)上面用@Transactional管理
@Transactional
public void transfer(String outname, String inname, Double money) {
//轉(zhuǎn)出
userDAO.out(outname, money);
//制造異常
//int i = 1/0;
//轉(zhuǎn)入
userDAO.in(inname, money);
}
}
----------------------------------------------------------------------------
需要將UserDAO也注冊(cè)成bean,將DataSource數(shù)據(jù)源傳入,調(diào)用父類(lèi)setDoataSource方法,創(chuàng)建一個(gè)JdbcTemplate,
這樣UserDAO就可以直接獲取父類(lèi)的JdbcTemplate使用了嘉栓。
但是,如果將@Autowired直接注解聲明的對(duì)象上,Spring會(huì)自動(dòng)創(chuàng)建一個(gè)setDataSource()方法,與父類(lèi)的final沖突拓诸。
因此自己定義一個(gè)set方法接收DataSource,調(diào)用父類(lèi)的setDSataSource方法胸懈。
@Repository("userDAO") // 將其注冊(cè)成bean
public class UserDAO extends JdbcDaoSupport {
//使用注解@Autowired注入DataSource數(shù)據(jù)源會(huì)默認(rèn)生成setter方法,setDataSource(Datasource ds)注入
//但是父類(lèi)的setDataSource是用final修飾的,不能重寫(xiě),而且這樣也無(wú)法將dataSource傳入到setDataSource方法中
//這樣就無(wú)法生成配置了注入數(shù)據(jù)源的JdbcTemplate,因此我們隨便寫(xiě)一個(gè)set方法,參數(shù)類(lèi)型寫(xiě)DataSource調(diào)用父類(lèi)的setter方法
//@Autowired
//private DataSource dataSource;
@Autowired
public void setSuperDataSource(DataSource dataSource) {
super.setDataSource(dataSource);
}
// 轉(zhuǎn)出
public void out(String outname, Double money) {
String sql = "update user set acount=acount-? where username=?";
getJdbcTemplate().update(sql, money, outname);
}
// 轉(zhuǎn)入
public void in(String inname, Double money) {
String sql = "update user set acount=acount+? where username=?";
getJdbcTemplate().update(sql, money, inname);
}
}
4. 配置注解驅(qū)動(dòng)事務(wù)管理器
<?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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 開(kāi)啟注解掃描組件 -->
<context:component-scan base-package="com.itdream" />
<!-- 引入外部配置文件(首先引入Context頭約束) -->
<context:property-placeholder location="db.properties" />
<!-- 配置C3P0數(shù)據(jù)源,使用${key}引入外部配置文件中的變量 -->
<bean id="dataSource" class="${jdbc.dataSourceClass}">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 配置具體的事務(wù)驅(qū)動(dòng)管理器:jdbc。
因?yàn)椴煌某志脤臃桨?需要用到不同的連接來(lái)管理事務(wù),因此需要傳入數(shù)據(jù)源(如果是hibernate就傳入sessionFactory)
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注冊(cè)事務(wù)注解驅(qū)動(dòng) -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
-------------------------------------------------------------------------
1. 事務(wù)的相關(guān)策略:
isolation,read-only...可以直接在@Transactional后配置
2. 如果在類(lèi)上標(biāo)識(shí)@Transactional,那么會(huì)對(duì)該類(lèi)中的所有public方法都包裝事務(wù),等同于所有的public方法上面
都添加了@Transactional恰响。
如果某個(gè)方法需要單獨(dú)的事務(wù)定義,需要在方法上加@Transactional來(lái)覆蓋類(lèi)上的標(biāo)注聲明趣钱。
xml和注解的選擇:
XML方式,集中式維護(hù)胚宦。使用XML進(jìn)行事務(wù)管理 屬性集中配置首有,便于管理和維護(hù)
注解方式,使用@Transactional注解進(jìn)行事務(wù)管理枢劝,配置太分散
因此優(yōu)選使用XML進(jìn)行事務(wù)管理井联。
事務(wù)的策略通配符設(shè)置:
xml方式與注解方式管理事務(wù)小結(jié):
今日總結(jié):
以后直接使用即可。
1. 注解AOP編程:
1. 確定目標(biāo)類(lèi)bean
2. 確定增強(qiáng)(通知)類(lèi),bean
3. 使用@Aspect定義切面,使用@Pointcut定義切入點(diǎn)您旁。
在對(duì)應(yīng)的增強(qiáng)方法上使用@Before,@Around等完成切入點(diǎn)與通知的關(guān)聯(lián)
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">
<!-- 開(kāi)啟注解掃描組件 -->
<context:component-scan base-package="com.itdream.spring.aopanno"/>
<!-- 開(kāi)啟AspectJ注解自動(dòng)代理機(jī)制:
作用:能自動(dòng)掃描帶有@Aspect注解的bean,將其作為aop增強(qiáng)配置,有點(diǎn)類(lèi)似于aop-config
-->
<aop:aspectj-autoproxy/>
</beans>
這里如果想使用cglib的代理,還可以在 <aop:aspectj-autoproxy/>內(nèi)設(shè)置proxy-target-class="true"
2. JdbcTemplate
為簡(jiǎn)化數(shù)據(jù)庫(kù)操作,Spring提供了JdbcTemplate模板類(lèi),為了簡(jiǎn)化JdbcTemplate的開(kāi)發(fā),Spring提供了JdbcDaoSupport烙常。
Dao層繼承該類(lèi),傳入對(duì)應(yīng)數(shù)據(jù)源就可以直接獲取對(duì)應(yīng)的Template操作數(shù)據(jù)庫(kù)。
JdbcTemplate/HibernateTemplate...
---------------------------------------------------------------------------
1. db.properties外部配置文件
jdbc.dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root
2. 在applicationContext.xml中讀取抽取出去的變量
首先要使用context:property-placeholder標(biāo)簽引入外界配置文件。
1. 因此首先要導(dǎo)入,context有關(guān)的schema約束蚕脏。
2. 引入外界配置文件設(shè)置
3. 引入變量
<!--引入頭約束 -->
<?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"
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">
<!-- 引入外部配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置C3P0數(shù)據(jù)源(連接池) -->
<bean id="dataSource" class="${jdbc.dataSource}">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.jdbcUrl}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
............................
</beans>
3. 聲明式事務(wù)管理
兩種方式:
-
XML
配置進(jìn)行事務(wù)管理 - 注解配置事務(wù)管理
注解配置進(jìn)行事務(wù)管理:
1. 將目標(biāo)類(lèi)定義成bean即可.增強(qiáng)類(lèi)我們不需自己實(shí)現(xiàn)侦副。
2. 在需要進(jìn)行事務(wù)管理的方法/類(lèi)上使用@Transactional(這里可以配置事務(wù)策略)
3. 配置注解事務(wù)管理器
applicationContext.xml配置注解驅(qū)動(dòng)事務(wù)管理器:
<?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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 開(kāi)啟注解掃描組件 -->
<context:component-scan base-package="com.itdream" />
<!-- 引入外部配置文件(首先引入Context頭約束) -->
<context:property-placeholder location="db.properties" />
<!-- 配置C3P0數(shù)據(jù)源,使用${key}引入外部配置文件中的變量 -->
<bean id="dataSource" class="${jdbc.dataSourceClass}">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 配置具體的事務(wù)驅(qū)動(dòng)管理器:jdbc。
因?yàn)椴煌某志脤臃桨?需要用到不同的連接來(lái)管理事務(wù),因此需要傳入數(shù)據(jù)源(如果是hibernate就傳入sessionFactory)
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注冊(cè)事務(wù)注解驅(qū)動(dòng) -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
XML
配置事務(wù)管理:【推薦】
1. 確定目標(biāo)類(lèi),注冊(cè)bean
2. 確定增強(qiáng)類(lèi),注冊(cè)bean(Spring已經(jīng)實(shí)現(xiàn),只需注冊(cè)該則增強(qiáng)類(lèi)即可)
3. 配置事務(wù)管理器(Spring實(shí)現(xiàn)的增強(qiáng)類(lèi)需要注入事務(wù)管理器)
4. 配置切面(切入點(diǎn)與通知的關(guān)聯(lián))
外部配置文件db.properties:
jdbc.dataSourceClass=com.mchange.v2.c3p0.ComboPooledDataSource
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root
applicationContext.xml配置文件最終版:
<!-- 引入外部配置文件(首先引入Context頭約束) -->
<?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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
<!-- 引入外界配置屬性 -->
<context:property-placeholder location="db.properties"/>
<!-- 配置數(shù)據(jù)源(連接池),根據(jù)選擇的不同連接池確定具體的class以及name -->
<bean id="dataSource" class="${jdbc.dataSourceClass}">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 事務(wù)管理 -->
<!-- 1.注冊(cè)增強(qiáng)類(lèi),2.注入事務(wù)管理器,3.確定事務(wù)策略 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer"/>
<tx:method name="save*"/>
<tx:method name="delete*"/>
<tx:method name="update*"/>
<tx:method name="find*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 注冊(cè)事務(wù)管理器,注入數(shù)據(jù)源,提供連接管理事務(wù) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置切面(切入點(diǎn)與通知的關(guān)系) -->
<aop:config>
<!-- 定義切入點(diǎn) -->
<aop:pointcut expression="execution(* com.itdream.service.UserService.transfer(..))" id="myPointcut"/>
<!-- 配置切入點(diǎn)和通知的關(guān)聯(lián) -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
</aop:config>
<!-- 注冊(cè)UserDAO -->
<bean id="userDAO" class="com.itdream.dao.UserDAO">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注冊(cè)UserService-->
<bean id="userService" class="com.itdream.service.UserService">
<property name="userDAO" ref="userDAO"/>
</bean>
</beans>