Spring JdbcTemplate&聲明式事務

一、JdbcTemplate基本使用


1)、JdbcTemplate基本使用-概述(瞭解)

JdbcTemplate是spring框架中提供的一個對象,是對原始繁瑣的Jdbc API對象的簡單封裝。spring框架爲咱們提供了不少的操做模板類。例如:操做關係型數據的JdbcTemplate和HibernateTemplate,操做nosql數據庫的RedisTemplate,操做消息隊列的JmsTemplate等等。

2)、JdbcTemplate基本使用-開發步驟(理解)

①導入spring-jdbc和spring-tx(事務)座標

②建立數據庫表和實體  

③建立JdbcTemplate對象  設置鏈接池

④執行數據庫操做

3)、JdbcTemplate基本使用-快速入門代碼實現(應用)

①導入Spring-jdbc和Spring-tx座標(依賴)php

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.0.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.0.5.RELEASE</version>
    </dependency>

<!--使用jdk1.8版本編譯-->
<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

②建立數據庫表和實體java

package com.ppvir.domain;

public class Account {

    private String name;
    private double money;

    public String getNa me() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

③建立JdbcTemplate對象 設置鏈接池 ④執行數據庫操做mysql

@Test
    //測試JdbcTemplate開發步驟
    public void test1() throws PropertyVetoException {
        //2,建立數據源對象,c3p0鏈接池
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        //數據庫參數設置
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUser("root");
        dataSource.setPassword("root");

        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //1,設置數據源對象  知道數據庫在哪
        jdbcTemplate.setDataSource(dataSource);
        //三、執行數據庫操做
        int row = jdbcTemplate.update("insert into account values(?,?)", "java", 18000);
        System.out.println(row);

    }

4)、JdbcTemplate基本使用-spring產生模板對象分析(理解)

咱們能夠將JdbcTemplate的建立權交給Spring, 將數據源DataSource的建立權也交給Spring, 在Spring容器內部將數據源DataSource注入到JdbcTemplate模版對象中, 而後經過Spring容器得到JdbcTemplate對象來執行操做。spring

注入與被注入對象都必須在spring容器中sql

5)、JdbcTemplate基本使用-spring產生模板對象代碼實現(應用)

在上面例子的基礎上,編寫applicationContext.xml配置數據源對象 配置:數據庫

applicationContext.xml
<!--數據源鏈接池對象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPoolDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/aop"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
 </bean>
<!--jdbc模版對象-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
</bean>

測試代碼:express

/**
     * 測試Spring產生jdbcTemplate對象
     */
    @Test
    public void testTemplate() throws Exception{
       //加載配置文件
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        //獲取spring容器中初始化的getBean
        JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);
        //c操做數據庫
        jdbcTemplate.update("insert into account(name,money) VALUES(?,?)","js",19990);
    }

6)、JdbcTemplate基本使用-spring產生模板對象代碼實現(抽取jdbc.properties)(應用)

將數據庫的鏈接信息抽取到外部配置文件中,和spring的配置文件分離開,有利於後期維護
jdbc.propreties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/aop
jdbc.username=root
jdbc.password=root

修改配置文件:apache

<!--加載jdbc.properties-->
<context:property-placeholder location="classpath:jdbc,properties">
<!--數據源對象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
</bean>

7)、JdbcTemplate基本使用-經常使用操做-更新操做&查詢操做(應用)

使用註解注入編程

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcTemplateAnnoTest {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 更新操做
     */
    @Test
    public void updateTest(){
        jdbcTemplate.update("update account set money=? where name=?",10000,"java");
    }

    @Test
    /**
     * 刪除操做
     */
    public void delTest(){
        jdbcTemplate.update("delete from account where name=?","php");
    }

    //查詢全部
    @Test
    public void queryAllTest(){
        List<Account> accountList = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<>(Account.class));
        for (Account account : accountList) {
            System.out.println(account);
        }
    }
    //查詢一個
    @Test
    public void queryOneTest(){
        Account name = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<>(Account.class), "java");
        System.out.println(name);
    }
    //聚合查詢
    @Test
    public void queryCountTest(){
        Long aLong = jdbcTemplate.queryForObject("select count(*) from account", long.class);//requiedType
        System.out.println(aLong);
    }

}

###9)、JdbcTemplate基本使用-知識要點(理解,記憶)api

  • 導入spring-jdbc和spring-tx座標依賴
  • 建立數據庫表和實體
  • 建立jdbcTemplate對象
    • JdbcTemplate jdbcTemplate = newJdbcTemplate();
    • jdbcTemplate.setDataSource(dataSource);
  • 執行數據庫CRUB操做
更新操做:

    jdbcTemplate.update (sql,params)

查詢操做:

    jdbcTemplate.query (sql,Mapper,params)//多個對象

    jdbcTemplate.queryForObject(sql,Mapper,params)//單個對象

#二、聲明式事務控制


***事務:***不可分割的操做要麼同時成功要麼同時失敗 聲明式事務控制=AOP+編程式事務控制,在xml配置文件中聲明

###2.一、編程式事務控制相關的對象 概念:經過java代碼手動開啓事務,提交事務,回滾事務。 #####2.1.一、PlatformTransactionManager (平臺事務管理器) PlatformTransactionManager 接口是 spring 的事務管理器,它裏面提供了咱們經常使用的操做事務的方法 平臺事務管理器

注意: PlatformTransactionManager 是接口類型,不一樣的 Dao 層技術則有不一樣的實現類,經過配置告訴spring,集成的哪一個框架,spring根據不一樣的框架選擇不一樣的操做。

Dao層的技術 實現類
jdbc 或 mybatis org.springframework.jdbc.datasource.DataSourceTransactionManager
hibernate(架構) org.springframework.orm.hibernate5.HibernateTransactionManager

#####2.1.二、 TransactionDefinition(事務的詳細配置信息存放) 封裝事務的參數 TransactionDefinition 是事務的定義信息對象,裏面有以下方法:

方法 說明
int getIsolationLevel() 得到事務的隔離級別
int getPropogationBehavior() 得到事務的傳播行爲
int getTimeout() 得到超時時間
boolean isReadOnly 是否只讀
  • 1.事務的隔離級別 設置隔離級別,能夠解決事務併發產生的問題,如髒讀、不可重複讀和虛讀(幻讀)。
    • ISOLATION_DEFAULT
    • ISOLATION_READ_UNCOMMITTED//讀未提交的數據 髒讀不可重複讀
    • ISOLATION_READ-COMMITTED//讀已提交數據,可是容許其餘人修改
    • ISOLATION-REPEATABLE_READ//讀到提交的數據,同時不容許別人修改,容許增刪。
    • ISOLATION_SERIALIZEBLE//讀到提交的數據,同時不容許別人任何操做。
  • 2.事務的傳播行爲 主要做用是 解決業務方法調用業務方法時統一
    • REQUIRED:required若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中。通常的選擇(默認值)有就用,沒有就建立
    • SUPPORTS:支持當前事務,若是當前沒有事務,就以非事務方式執行(沒有事務)有就用,沒有就不用
    • MANDATORY:使用當前的事務,若是當前沒有事務,就拋出異常
    • REQUERS_NEW:新建事務,若是當前在事務中,把當前事務掛起。
    • NOT_SUPPORTED:以非事務方式執行操做,若是當前存在事務,就把當前事務掛起 有沒有都不用
    • NEVER:以非事務方式運行,若是當前存在事務,拋出異常
    • NESTED:若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則執行 REQUIRED 相似的操做
    • 超時時間:默認值是-1,沒有超時限制。若是有,以秒爲單位進行設置 timwout
    • 是否只讀:建議查詢時設置爲只讀 read-only #####2.1.三、 TransactionStatus(獲取事務的狀態信息) TransactionStatus 接口提供的是事務具體的運行狀態,方法介紹以下。

狀態是被動信息,不是主動設置的。

平臺事務管理器(指定事務控制行爲)+事務定義對象(封裝事務的參數)=事務狀態對象(被動的封裝程序的動態信息)

方法 說明
boolean hasSavepoint() 是否存儲滾回點
boolean isCompleted() 事務是否完成
boolean isNewTransaction() 是不是新事務
boolean isRollbackOnly() 事務是否滾回

###2.二、 基於xml的聲明式事務控制(方便統一配置) #####2.2.1 什麼是聲明式事務控制

Spring 的聲明式事務顧名思義就是採用聲明的方式來處理事務。這裏所說的聲明,就是指在配置文件中聲明,用在 Spring 配置文件中聲明式的處理事務來代替代碼式的處理事務。

聲明式事務控制=AOP+編程式事務控制,在xml配置文件中聲明

聲明式事務處理的做用

  • 事務管理不侵入開發的組件(解耦性)。具體來講,業務邏輯對象就不會意識到正在事務管理之中,事實上也應該如此,由於事務管理是屬於系統層面的服務,而不是業務邏輯的一部分,若是想要改變事務管理策劃的話,也只須要在定義文件中從新配置便可
  • 在不須要事務管理的時候,只要在設定文件上修改一下,便可移去事務管理服務,無需改變代碼從新編譯,這樣維護起來極其方便

注意:Spring 聲明式事務控制底層就是AOP。 #####2.2.二、聲明式事務控制的體現

聲明式事務控制 明確事項:

誰是切點,哪一個是將要被加強的方法 誰是通知,加強方法 配置切面 ①配置文件引入tx命名空間

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
       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
">

②配置事務加強 & 事務AOP織入

<!--在上面引入tx aop命名空間-->

    <!--
        配置事務加強:
            1.平臺事務管理器
            2.事務加強配置
            3.配置事務AOP織入
    -->
    <!--1.告訴spring使用什麼框架來操做數據庫,不一樣的框架,底層操做事務的方式是不一樣的bean-->
    <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--2.事務加強配置 tx-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes><!--事務的屬性-->
            <tx:method name="*"/><!--對切點(方法)進行加強 *:表明加強全部的切點(方法)-->
        </tx:attributes>
        <!--
        切點方法的事務參數配置
        <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
        - name:切點方法名稱
        - isolation:事務的隔離級別
        - propogation:事務的傳播行爲
        - timeout:超時時間
        - read-only:是否只讀

        -->
    </tx:advice>
    <!--3.配置事務AOP織入-->
    <aop:config>
        <!--抽取切點表達式-->
        <aop:pointcut id="myPointcut" expression="execution(* *cn.ppvir.service.impl.*.*(..))"/>
        <!--織入-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"></aop:advisor>
    </aop:config>

#####2.2.三、小結要點 聲明式事務控制的配置要點

  • 平臺事務管理器的配置,告訴spring將要使用哪套api進行配置
  • 事務通知的配置,事務加強
    • 參數配置,通配或者單獨配置
  • 事務aop織入的配置
    • adviser表明只有一個通知
    • 切點表達式也能夠對外進行抽取
      • <aop:pointcut id="myPointcut" expression="execution(* *cn.ppvir.service.impl.*.*(..))"/>

###2.三、基於註解的聲明式事務控制 #####2.3.一、 使用註解配置聲明式事務控制

使用註解在xml中配置組件掃描<context:componet-scan/>,建議使用場景:

註解使用通常是自定義的bean,由於能夠拿到源碼 *XML * 通常是非自定義的bean 註解@Transactional(事務參數),能夠在類上或方法上,或單獨配置,如包含多層註解事務控制,就近原則執行。

  • 編寫AccountDao,@Respostitory() 註解DAO配置bean、@Autowired自動注入
  • 編寫AccountService, @Service()註解Service配置bean @Transactional()註解事務通知的配置
/**
1) AccountDao
 * 數據庫操做的實現類
 * 註解方式@Respository("accountDao")
 */
@Repository("accountDao")
public class AccountDao implements IAccountDao {
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void out(String outMan, double money) {
        jdbcTemplate.update("update account set money=money-? where name=?",money,outMan);

    }
    @Override
    public void in(String inMan, double money) {
        jdbcTemplate.update("update account SET money=money+? where name=?",money,inMan);

    }
    @Override
    public void queryAll() {
        List<Account> accountList = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<>(Account.class));
        for (Account account : accountList) {
            System.out.println(account);
        }
    }
}

/**
2)AccountService
 * 具體的業務操做實現類
 */
@Service("accountService") 
@Transactional(isolation = Isolation.READ_COMMITTED)//註解事務通知配置
public class AccountServiceImpl implements IAccountService {
    @Autowired
    private IAccountDao accountDao;

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED)
    public void transfer(String outMan, String inMan, double money) {
        accountDao.out(outMan,money);
        //int m= 2/0;//java.lang.ArithmeticException: / by zero
        accountDao.in(inMan,money);
    }

    @Override
    public void findAll() {
        accountDao.queryAll();
    }
}
  • 編寫applicationContext.xml配置文件
<!--只包含新添加的組件掃描 和 事務的註解驅動 配置-->
<!--組件掃描-->
    <context:component-scan base-package="cn.ppvir"></context:component-scan>
<!--事務註解驅動--><!--驅動是開關,加上之後註解才能啓動-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

#####2.3.二、註解配置聲明式事務控制解析 ①使用 @Transactional 在須要進行事務控制的類或是方法上修飾,註解可用的屬性同 xml 配置方式,例如隔離級別、傳播行爲等。

②註解使用在類上,那麼該類下的全部方法都使用同一套註解參數配置。

③使用在方法上,不一樣的方法能夠採用不一樣的事務參數配置。

④Xml配置文件中要開啓事務的註解驅動<tx:annotation-driven />

#####2.3.三、小結要點 註解聲明式事務控制的配置要點

  • 平臺事務管理器配置(xml方式)
  • 事務通知的配置(@Transactional註解配置)
  • 事務註解驅動的配置<tx:annotation-driven transaction-manager="transactionManager"/>
相關文章
相關標籤/搜索