03_Spring_注解AOP編程&jdbcTemplate&聲明事務(wù)

一掏膏、@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();
    }
}

img36.png

補(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)行代理?可以颠区!
img37.png
這里要使用子類(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 
img39.png

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é)果:

img40.png

另外部服,一個(gè)通知方法也可以對(duì)多個(gè)切入點(diǎn)進(jìn)行增強(qiáng):

img41.png

二、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 )

img42.png
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ā)

img43.png
上面我們使用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è)試:

img44.png

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
  • 復(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):

img45.png
  • 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í)別
img46.png

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)題

img47.png

業(yè)務(wù)層兩個(gè)方法面臨的事務(wù)問(wèn)題:有些時(shí)候需要處于同一個(gè)事務(wù)怒医,有些時(shí)候不能在同一個(gè)事務(wù) 炉抒!

事務(wù)的傳播行為的7種類(lèi)型:

img48.png

有關(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)系:

  1. 用戶(hù)管理事務(wù),需要先配置TransactionDefinition(事務(wù)定義信息元媚、事務(wù)的管理方案)轧叽;
  2. 然后根據(jù)TransactionDefinition,通過(guò)TransactionManager(事務(wù)管理器)進(jìn)行事務(wù)管理刊棕;
  3. 事務(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包:

img49.png
    
    創(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)注聲明趣钱。
img50.png

xml和注解的選擇:

XML方式,集中式維護(hù)胚宦。使用XML進(jìn)行事務(wù)管理 屬性集中配置首有,便于管理和維護(hù)

注解方式,使用@Transactional注解進(jìn)行事務(wù)管理枢劝,配置太分散

因此優(yōu)選使用XML進(jìn)行事務(wù)管理井联。


事務(wù)的策略通配符設(shè)置:

img51.png

xml方式與注解方式管理事務(wù)小結(jié):

img52.png
img53.png

今日總結(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>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末驼鞭,一起剝皮案震驚了整個(gè)濱河市秦驯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挣棕,老刑警劉巖译隘,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異洛心,居然都是意外死亡固耘,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)词身,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)玻驻,“玉大人,你說(shuō)我怎么就攤上這事偿枕¤邓玻” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵渐夸,是天一觀的道長(zhǎng)嗤锉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)墓塌,這世上最難降的妖魔是什么瘟忱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮苫幢,結(jié)果婚禮上访诱,老公的妹妹穿的比我還像新娘。我一直安慰自己韩肝,他們只是感情好触菜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著哀峻,像睡著了一般涡相。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上剩蟀,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天催蝗,我揣著相機(jī)與錄音,去河邊找鬼育特。 笑死丙号,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播犬缨,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼喳魏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了遍尺?” 一聲冷哼從身側(cè)響起截酷,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤涮拗,失蹤者是張志新(化名)和其女友劉穎乾戏,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體三热,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鼓择,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了就漾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呐能。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖抑堡,靈堂內(nèi)的尸體忽然破棺而出摆出,到底是詐尸還是另有隱情,我是刑警寧澤首妖,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布偎漫,位于F島的核電站,受9級(jí)特大地震影響有缆,放射性物質(zhì)發(fā)生泄漏象踊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一棚壁、第九天 我趴在偏房一處隱蔽的房頂上張望杯矩。 院中可真熱鬧,春花似錦袖外、人聲如沸史隆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逆害。三九已至,卻和暖如春蚣驼,著一層夾襖步出監(jiān)牢的瞬間魄幕,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工颖杏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纯陨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像翼抠,于是被迫代替她去往敵國(guó)和親咙轩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,810評(píng)論 6 342
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理阴颖,服務(wù)發(fā)現(xiàn)活喊,斷路器,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • 什么是Spring Spring是一個(gè)開(kāi)源的Java EE開(kāi)發(fā)框架量愧。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,462評(píng)論 1 133
  • OC使用swift 在oc項(xiàng)目中使用swift簡(jiǎn)單到爆钾菊,只需要導(dǎo)入一個(gè)頭文件#import "XXXXX-Swif...
    Yochi閱讀 280評(píng)論 0 0
  • 最近感到壓力倍增。現(xiàn)在將這兩種狀態(tài)都記下來(lái)偎肃,作為對(duì)比煞烫。 辭職之前的狀態(tài),滿(mǎn)心歡喜要辭職累颂,在公司呆多一天都是對(duì)自己的...
    田永威閱讀 630評(píng)論 0 0