Spring 应用之Spring JDBC实现

jdbcTemplate类的入门

方式一

POM.XML

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>spring-aop</groupId>
    <artifactId>spring-aop</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <!-- spring ioc组件须要的依赖包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <!-- 基于AspectJ的aop依赖包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- spring 事务管理和JDBC依赖包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <!-- spring 单元测试组件包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.1.RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- MySql数据库驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>
    </dependencies>
</project>

修改jdk版本html

<build>
        <plugins>
            <!-- 配置Maven的JDK编译级别 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

 测试单元

package com.cyb.spring.test; import org.junit.Test; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; public class TestJdbcTemplate { @Test public void test() { try { //建立链接池,先使用spring框架内置的链接池
            DriverManagerDataSource dataSource =new DriverManagerDataSource(); //数据库驱动程序 //dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //旧驱动程序
            dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); //新驱动程序 //数据库链接字符串
            dataSource.setUrl("jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"); //帐号
            dataSource.setUsername("root"); //密码
            dataSource.setPassword("root"); //建立模板类
            JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource); //完成数据的添加
            int res = jdbcTemplate.update("insert into s_user values (null,?,?)",22,"测试人员"); } catch (Exception e) { e.printStackTrace(); } } }

 方式二

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/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">
    <!-- 管理DataSource -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!-- set方法注入属性,和类中的成员属性无关,和set方法名称有关,好比有一个属性叫username,可是set方法:setName -->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/demo?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <!-- 管理jdbcTemplate -->
    <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
</beans>

单元测试

package com.cyb.spring.test; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring.xml") public class TestJdbcTemplate { @Autowired private JdbcTemplate jdbcTemplate; @Test public void test() { try { int res = jdbcTemplate.update("insert into s_user values (null,?,?)",22,"测试人员"); } catch (Exception e) { e.printStackTrace(); } } }

Spring 管理第三方DataSource

经常使用数据源链接池

  • dbcp
  • c3p0
  • druid(阿里出品)

管理DBCP链接池

 maven工程加入依赖java

pom.xmlmysql

<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>

spring.xmlspring

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/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">
    <!-- 管理第三方DataSource -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <!-- set方法注入属性,和类中的成员属性无关,和set方法名称有关,好比有一个属性叫username,可是set方法:setName -->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/demo?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <!-- 管理jdbcTemplate -->
    <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
</beans>

单元测试sql

package com.cyb.spring.test; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring.xml") public class TestJdbcTemplate { @Autowired private JdbcTemplate jdbcTemplate; @Test public void test() { try { int res = jdbcTemplate.update("insert into s_user values (null,?,?)",22,"测试人员22"); } catch (Exception e) { e.printStackTrace(); } } @Test public void test2() { try { //建立链接池,先使用spring框架内置的链接池
            DriverManagerDataSource dataSource =new DriverManagerDataSource(); //数据库驱动程序 //dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //旧驱动程序
            dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); //新驱动程序 //数据库链接字符串
            dataSource.setUrl("jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"); //帐号
            dataSource.setUsername("root"); //密码
            dataSource.setPassword("root"); //建立模板类
            JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource); //完成数据的添加
            int res = jdbcTemplate.update("insert into s_user values (null,?,?)",22,"测试人员"); } catch (Exception e) { e.printStackTrace(); } } }

使用JdbcTemplate完成增删改查操做

 s_user.java数据库

package com.cyb.spring.test; public class s_user { private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "s_user [id=" + id + ", name=" + name + ", age=" + age + "]"; } private String name; private int age; }

TestjdbcTemplate.javaexpress

查询

package com.cyb.spring.test; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring.xml") public class TestJdbcTemplate { @Autowired private JdbcTemplate jdbcTemplate; @Test public void test() { //第一个参数:执行的sql语句 //第二个参数:结果映射处理器(RowMapper) //第三个参数:sql语句中的入参
        List<s_user> queryList = jdbcTemplate.query("select * from s_user",new MyBeanMapper(),null); System.out.println(queryList); } } class MyBeanMapper implements RowMapper { public s_user mapRow(ResultSet rs, int rowNum) throws SQLException { s_user user=new s_user(); user.setId(rs.getInt("id")); user.setName(rs.getString("name")); user.setAge(rs.getInt("age")); return user; } }

插入

package com.cyb.spring.test; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring.xml") public class TestJdbcTemplate { @Autowired private JdbcTemplate jdbcTemplate; @Test public void test() { try { int res = jdbcTemplate.update("insert into s_user values (null,?,?)",22,"测试人员22"); } catch (Exception e) { e.printStackTrace(); } } }

更新

package com.cyb.spring.test; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring.xml") public class TestJdbcTemplate { @Autowired private JdbcTemplate jdbcTemplate; @Test public void test() { try { int res = jdbcTemplate.update("update s_user set name=?,age=? where id=?","测试人员",19,5); } catch (Exception e) { e.printStackTrace(); } } }

删除

package com.cyb.spring.test; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring.xml") public class TestJdbcTemplate { @Autowired private JdbcTemplate jdbcTemplate; @Test public void test() { try { int res = jdbcTemplate.update("delete from s_user where id=?",5); } catch (Exception e) { e.printStackTrace(); } } }

 Spring DAO 开发之JdbcDaoSupport

案例设计

  1. 编写转帐案例(包括业务层和持久层)
  2. 编写DAO时引入JdbcDaoSupport的使用

实现

 项目结构图apache

 

 

 

 

 数据库表字段编程

 

 pom.xmlapi

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>spring-aop</groupId>
    <artifactId>spring-aop</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <!-- spring ioc组件须要的依赖包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <!-- 基于AspectJ的aop依赖包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- spring 事务管理和JDBC依赖包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <!-- spring 单元测试组件包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.1.RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- MySql数据库驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>
        <!-- dbcp链接池依赖包 -->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.1</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- 配置Maven的JDK编译级别 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

AccountDao.java

package com.cyb.spring.dao; public interface AccountDao { void update(String name, int money); int queryMoney(String name); }

AccountDaoImpl.java

方式一

package com.cyb.spring.dao; import java.sql.ResultSet; import java.sql.SQLException; import javax.annotation.Resource; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Repository; @Repository public class AccountDaoImpl implements AccountDao { @Resource private JdbcTemplate jdbcTemplate; public void update(String name, int money) { // jdbc操做 // MyBatis操做 // JdbcTemplate操做
        jdbcTemplate.update("UPDATE s_account set money=" + money + " where name='" + name + "'"); } public int queryMoney(String name) { int money = jdbcTemplate.queryForObject("select money from s_account where name=?", new IntMapper(), name); return money; } } class IntMapper implements RowMapper<Integer> { public Integer mapRow(ResultSet rs, int rowNum) throws SQLException { return rs.getInt("money"); } }

方式二

package com.cyb.spring.dao; import java.sql.ResultSet; import java.sql.SQLException; import javax.annotation.Resource; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.stereotype.Repository; @Repository public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { public void update(String name, int money) { this.getJdbcTemplate().update("UPDATE s_account set money=" + money + " where name='" + name + "'"); } public int queryMoney(String name) { int money=this.getJdbcTemplate().queryForObject("select money from s_account where name=?", new IntMapper(), name); return money; } } class IntMapper implements RowMapper<Integer> { public Integer mapRow(ResultSet rs, int rowNum) throws SQLException { return rs.getInt("money"); } }

AccountService.java

package com.cyb.spring.service; public interface AccountService { void transfer(String from, String to, int money); }

AccountServiceImpl.java

方式一

package com.cyb.spring.service; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.cyb.spring.dao.AccountDao; @Service public class AccountServiceImpl implements AccountService { @Resource private AccountDao dao; public void transfer(String from, String to, int money) { //先查询from帐户的钱
        int fromMoney=dao.queryMoney(from); // 对from帐户进行扣钱操做
        dao.update(from, fromMoney-money); // 对to帐户加钱操做
        int toMoney=dao.queryMoney(to); dao.update(to, toMoney+money); } }

方式二

package com.cyb.spring.service; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.cyb.spring.dao.AccountDao; @Service public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public AccountDao getAccountDao() { return accountDao; } public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void transfer(String from, String to, int money) { //先查询from帐户的钱
        int fromMoney=accountDao.queryMoney(from); // 对from帐户进行扣钱操做
        accountDao.update(from, fromMoney-money); // 对to帐户加钱操做
        int toMoney=accountDao.queryMoney(to); accountDao.update(to, toMoney+money); } }

spring-transfer.xml

方式一

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 从底层往上层配 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <!-- set方法注入属性,和类中的成员属性无关,和set方法名称有关,好比有一个属性叫username,可是set方法:setName -->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/demo?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <!-- 管理jdbcTemplate -->
    <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    <!-- AccountDao和AccountService -->
    <context:component-scan base-package="com.cyb.spring"></context:component-scan>
</beans>

方式二

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 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
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 从底层往上层配 -->
    <bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <!-- set方法注入属性,和类中的成员属性无关,和set方法名称有关,好比有一个属性叫username,可是set方法:setName -->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/demo?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <!-- 管理jdbcTemplate -->
    <bean id="template"
        class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    <!-- AccountDao和AccountService -->
    <bean id="accountService"
        class="com.cyb.spring.service.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    <bean id="accountDao" class="com.cyb.spring.dao.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>

 

AccountServiceTest.java

package com.cyb.spring.service; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring-transfer.xml") public class AccountServiceTest { @Autowired private AccountService Service; @Test public void testTransfer() { Service.transfer("老公", "老婆", 500); } }

 Spring 应用之事务

 事务介绍

  •  事务:指的是逻辑上一组操做,组成这个事务的各个执行单元,要么一块儿成功,要么一块儿失败!
  • 事务的特性(ACID)
    • 原子性(Atomicty)
      • 原子性是指事务包含的全部操做要么所有成功,要么所有失败回滚。
    • 一致性(Consistency)
      • 一致性是指事务必须使数据库从一个一致性状态变换到另外一个一致性状态,也就是说一个事务执行以前和执行以后都必须处于一致性状态。
      • 拿转帐来讲,假设用户A和用户B二者的钱加起来一共是5000,那么无论A和B之间如何转帐,赚屡次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
    • 隔离性(Isolation)
      • 隔离性是当多个用户并发访问数据库时,好比操做同一张表时,数据库为每个用户开启的事务,不能被其余事务的操做所干扰,多个并发事务之间要相互隔离。
    • 持久性(Durability)
      • 持久性是指一个事务一旦被提交了,那么对数据库种的数据的改变就是永久性的,即使是在数据库系统遇到故障的状况下也不会丢失提交事务的操做。

 事务并发问题(隔离性致使)

在事务的并发操做可能会出现一些问题

  •  脏读:一个事务读取到另外一个事务未提交的数据
  • 不可重复读:一个事务因读取到另外一个事务已提交的数据。致使对同一条记录读取两次以上的结果不一致。update操做
  • 幻读:一个事务因读取到另外一个事务已提交的数据。致使对同一张表读取两次以上结果不一致。insert、delete操做

事务隔离级别

  为了不上面出现的几种状况,在标准SQL规范中,定义了4个事务隔离级别,不一样的隔离级别对事务的处理不一样。

四种隔离级别(由低到高):

  1. Read uncommitted(读未提交):最低级别,任何状况都没法保证。
  2. Read committed(读已提交):可避免脏读的发生
  3. Repeatable read(可重复读):可避免脏读、不可重复读的发生
  4. Serializable(串行化):可避免脏读、不可重复读、幻读的发生

默认隔离级别

  大多数数据库的默认隔离级别是Read committed,好比Oracle、DB2等。

  MySQL数据库的默认隔离级别是Repeatable read。

注意事项

  级别越高,越能保证数据的完整性和一致性,可是对并发性能的影响也越大。

  对于多数应用程序,能够优先考虑把数据库系统的隔离级别设为Read Committed。它可以避免脏读取,并且具备较好的并发性能。尽管它会致使不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,能够由应用程序采用悲观锁或乐观锁来控制。

 Spring 框架的事务管理相关的类和API

  Spring 并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。Spring事务管理器的接口是PlatformTransactionManager,经过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,可是具体的实现就是各个平台本身的事儿了。

 

 

 

 

1. PlatformTransactionManager接口     -- 平台事务管理器.(真正管理事务的类)。该接口有具体的实现类,根据不一样的持久层框架,须要选择不一样的实现类! 

2. TransactionDefinition接口          -- 事务定义信息.(事务的隔离级别,传播行为,超时,只读)

3. TransactionStatus接口              -- 事务的状态(是否新事务、是否已提交、是否有保存点、是否回滚)

 

4. 总结:上述对象之间的关系:平台事务管理器真正管理事务对象.根据事务定义的信息TransactionDefinition 进行事务管理,在管理事务中产生一些状态.将状态记录到TransactionStatus中

 

5. PlatformTransactionManager接口中实现类和经常使用的方法

    1. 接口的实现类

        * 若是使用的Spring的JDBC模板或者MyBatisIBatis)框架,须要选择DataSourceTransactionManager实现类

        * 若是使用的是Hibernate的框架,须要选择HibernateTransactionManager实现类

 

    2. 该接口的经常使用方法

        * void commit(TransactionStatus status)

        * TransactionStatus getTransaction(TransactionDefinition definition)

        * void rollback(TransactionStatus status)

 

6. TransactionDefinition

    1. 事务隔离级别的常量

        * static int ISOLATION_DEFAULT              -- 采用数据库的默认隔离级别

        * static int ISOLATION_READ_UNCOMMITTED

        * static int ISOLATION_READ_COMMITTED

        * static int ISOLATION_REPEATABLE_READ

        * static int ISOLATION_SERIALIZABLE

 

    2. 事务的传播行为常量(不用设置,使用默认值)

        * 先解释什么是事务的传播行为:解决的是业务层之间的方法调用!!

 

        * PROPAGATION_REQUIRED(默认值) -- A中有事务,使用A中的事务.若是没有,B就会开启一个新的事务,将A包含进来.(保证A,B在同一个事务中),默认值!!

        * PROPAGATION_SUPPORTS          -- A中有事务,使用A中的事务.若是A中没有事务.那么B也不使用事务.

        * PROPAGATION_MANDATORY         -- A中有事务,使用A中的事务.若是A没有事务.抛出异常.

 

        * PROPAGATION_REQUIRES_NEW      -- A中有事务,将A中的事务挂起.B建立一个新的事务.(保证A,B没有在一个事务中)

        * PROPAGATION_NOT_SUPPORTED     -- A中有事务,将A中的事务挂起.

        * PROPAGATION_NEVER             -- A中有事务,抛出异常.

 

        * PROPAGATION_NESTED            -- 嵌套事务.当A执行以后,就会在这个位置设置一个保存点.若是B没有问题.执行经过.若是B出现异常,运行客户根据需求回滚(选择回滚到保存点或者是最初始状态)

 Spring 框架事务管理的分类

1. Spring的编程式事务管理(不推荐使用)

        * 经过手动编写代码的方式完成事务的管理(不推荐)

 

2. Spring的声明式事务管理底层采用AOP的技术

        * 经过一段配置的方式完成事务的管理

编程式事务管理(了解)

1. 说明:Spring为了简化事务管理的代码:提供了模板类 TransactionTemplate,因此手动编程的方式来管理事务,只须要使用该模板类便可!!

 

2. 手动编程方式的具体步骤以下:

    1. 步骤一:配置一个事务管理器,Spring使用PlatformTransactionManager接口来管理事务,因此我们须要使用到他的实现类!!

        <!-- 配置事务管理器 -->

        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

            <property name="dataSource" ref="dataSource"/>

        </bean>

 

    2. 步骤二:配置事务管理的模板

        <!-- 配置事务管理的模板 -->

        <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

            <property name="transactionManager" ref="transactionManager"/>

        </bean>

 

    3. 步骤三:在须要进行事务管理的类中,注入事务管理的模板

        <bean id="accountService" class="com.itheima.demo1.AccountServiceImpl">

            <property name="accountDao" ref="accountDao"/>

            <property name="transactionTemplate" ref="transactionTemplate"/>

        </bean>

 

    4. 步骤四:在业务层使用模板管理事务:

        // 注入事务模板对象

        private TransactionTemplate transactionTemplate;

        public void setTransactionTemplate(TransactionTemplate transactionTemplate) {

            this.transactionTemplate = transactionTemplate;

        }

 

        public void pay(final String out, final String in, final double money) {

            transactionTemplate.execute(new TransactionCallbackWithoutResult() {

 

                protected void doInTransactionWithoutResult(TransactionStatus status) {

                    // 扣钱

                    accountDao.outMoney(out, money);

                    int a = 10/0;

                    // 加钱

                    accountDao.inMoney(in, money);

                }

            });

声明式事务管理(重点)

  1. 基于AspectJ的XML方式(重点掌握)
  2. 基于AspectJ的注解方式(重点掌握)

实现

基于XML方式

基于注解方式

准备转帐环境:

***业务层

***AccountService

***AccountServiceImpl

 

 

 

***持久层:

***AccountDao

***AccountDaoImpl

***spring配置

***单元测试代码

 

 

 

***配置事务管理的AOP

***平台事务管理器:DataSourceTransactionManager

***事务通知<tx:advice id=”” transaction-manager=””/>

***AOP配置:

<aop:config>

  <aop:advisor advice-ref=”” pointcut=””/>

</aop:config>

 

 

 源码分析tx:advisor

源码入口

此处须要了解TxAdviceBeanDefinitionParser的继承体系,TxAdviceBeanDefinitionParseràAbstractSingleBeanDefinitionParseràAbstractBeanDefinitionParser,由于根据上面loadBeanDefinitions流程源码分析,咱们知道自定义元素的解析工做是从一个namespaceHandler.parser方法开始的,该方法在AbstractBeanDefinitionParser类中

咱们重点关心如何获取BeanDefinition对象的,因此接下来,咱们进入parseInternal方法,该方法在AbstractSingleBeanDefinitionParser中(参考上面继承体系

接下来,咱们来到了TxAdviceBeanDefinitionParser类,由于getBeanClass方法和doParser方法都在该类里面

此时咱们重点了解一下TransactionInterceptor这个类,它是咱们分析的最终目标

invokeWithInTransaction方法在TransactionInterceptor类的父类TransactionAspectSupport

对于事务源码,了解到此处基本上能够了,若是想再了解事务是如何开启和提交的,请继续往下看,接下来咱们进入createTransactionIfNecessary方法看看,事务是如何开启的

咱们进入AbstractPlatformTransactionManager中的getTransaction方法继续了解事务是如何开启的

接下来,该进入doBegin方法了,不过该方法在具体的平台事务管理器的子类中,咱们此处使用DataSourceTransactionManager子类进行源码跟踪:

DataSourceTransactionManager的事务管理是经过底层的JDBC代码实现的,可是不一样的平台事务管理器,它们底层的事务处理也是不一样的。

事务管理之基于AspectJ的注解方式(重点掌握)

***service类上或者方法上加注解:

***类上加@Transactional:表示该类中全部的方法都被事务管理

***方法上加@Transactional:表示只有该方法被事务管理

***开启事务注解:

原文出处:https://www.cnblogs.com/chenyanbin/p/11832058.html