Spring笔记(四)——JDBC模板技术和事务管理

原创 2017年07月16日 15:22:22

对于Web开发,Spring提供了一站式的解决方案。表现web层,可以使用springmvc。持久层,spring提供了JDBC模板技术和数据库进行交互。
除了JDBC模板,还有Hibernate模板。
JDBC模板直接使用sql语言。

环境搭建

需要引入的包如下:
引入的包
数据库使用的是mysql,因此必须需要导入mysql的jar包。除此之外,还有 Spring-jdbc.jar和Spring-tx.jar。
Spring-jdbc.jar是Spring JDBC模板技术需要用到的jar包。
如果要使用事务,就需要引入Spring-tx.jar。
Spring的JDBC模板有自己的连接池,直接在配置文件中配置就可以使用。当然也可以使用C3P0和DBCP数据库连接池。引入相关jar包,配置文件中配置了就可以使用了。

首先创建数据库和表:

use study;

create table t_account(
        id int primary key auto_increment,
        name varchar(20),
        money double
    );

创建一个javaBean

public class Account {

    private Integer id;
    private String name;
    private Double money;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        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 [id=" + id + ", name=" + name + ", money=" + money + "]";
    }

}

applicationContext.xml配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--开启注解扫描,可以扫描com.mq包下的所有bean  -->
    <context:component-scan base-package="com.mq"/>

    <!-- 内置的连接池:先配置连接池  -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///study"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>


    <!-- 配置DBCP的连接池 
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///study"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
    -->

    <!-- 配置C3P0的连接池 -->
<!--    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///study"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
    </bean> -->

    <!-- 配置JDBC的模板类 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

注意,spring的JDBC模板自带数据库连接池。如果需要其他连接池,引入相关jar包再做配置。
必须配置模板类,将使用的连接池进行依赖注入
注意数据库的名称,账号和密码要和自己的一致

测试

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration("classpath:applicationContext.xml") 
public class MyTest {
    @Resource(name="jdbcTemplate")
    private JdbcTemplate jdbcTemplate;

    @Test
    public void f1(){
        jdbcTemplate.update("insert into t_account values (null,?,?)", "关羽",1000);
    }

    /**
     * update(String sql,Object...params)   可以完成增删改操作
     */
    @Test
    public void f2(){
        jdbcTemplate.update("update t_account set name = ? where id = ?","张飞",5);
    }

    /**
     * 删除测试
     */
    @Test
    public void f3(){
        jdbcTemplate.update("delete from t_account where id = ?",5);
    }

    /**
     * 测试查询:通过主键查询一条记录
     */
    @Test
    public void f4(){
        Account ac = jdbcTemplate.queryForObject("select * from t_account where id = ?", new BeanMapper(), 1);
        System.out.println(ac);
    }

    /**
     * 查询所有的数据
     */
    @Test
    public void f5(){
        List<Account> list = jdbcTemplate.query("select * from t_account", new BeanMapper());
        System.out.println(list);
    }

    /**
     * 自己手动的来封装数据(一行一行封装数据)
     * @author Administrator
     */
    class BeanMapper implements RowMapper<Account>{

        public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
            Account ac = new Account();
            ac.setId(rs.getInt("id"));
            ac.setName(rs.getString("name"));
            ac.setMoney(rs.getDouble("money"));
            return ac;
        }
    }

}

因为Spring的JDBC模板技术不想Hibernate那样提供数据库的表和javaBean之间的映射关系,所以需要自己写一个类实现RowMapper接口,完成这种映射关系。

事务管理

事务简介

  1. 事务:指的是逻辑上一组操作,组成这个事务的各个执行单元,要么一起成功,要么一起失败!
  2. 事务的特性

    • 原子性:要么全部成功,要么全部失败
    • 一致性:操作前后,总的状态保持不变。
    • 隔离性:并发事务之间互相影响的程度,比如一个事务会不会读取到另一个未提交的事务修改的数据。
    • 持久性:事务提交后,对系统的影响是永久的。
  3. 如果不考虑隔离性,引发安全性问题

    • 读问题:

      • 脏读:
      • 不可重复读:
      • 虚读:
    • 写问题:

      • 丢失更新:
  4. 如何解决安全性问题

    • 读问题解决,设置数据库隔离级别
    • 写问题解决可以使用 悲观锁和乐观锁的方式解决

平台事务管理器:PlatformTransactionManager接口

平台事务管理器.(真正管理事务的类)。该接口有具体的实现类,根据不同的持久层框架,需要选择不同的实现类!
* 如果使用的Spring的JDBC模板或者MyBatis框架,需要选择DataSourceTransactionManager实现类
* 如果使用的是Hibernate的框架,需要选择HibernateTransactionManager实现类

该接口常用的方法
* void commit(TransactionStatus status) :提交事务
* TransactionStatus getTransaction(TransactionDefinition definition) :获取事务
* void rollback(TransactionStatus status) :回滚。

Spring事务的管理有两种方式,一种是编程式事务管理,一种是声明式事务管理。
注意,虽然事务是数据库相关的内容,但开发中,在业务层管理事务。
编程式事务管理不推荐使用,声明式事务管理是重点。
声明式事务管理有两种方式,一种是配置xml文件的方式,一种是注解的方式。
注解方式最简洁,这里主要就说说注解方式。

说起事务,最典型的问题莫过于转账问题,两个不同的账户上,钱的进和出必须同一时刻完成,要不一起失败,要么一起成功。
使用Spring的事务管理,需要额外引入:
com.springsource.org.aopalliance-1.0.0.jar
使用注解的方式时,需要在配置文件中开启事务的注解:

<tx:annotation-driven transaction-manager="transactionManager"/>

配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--开启注解扫描,可以扫描com.mq包下的所有bean  -->
    <context:component-scan base-package="com.mq"/>

    <!-- 开启事务的注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- 内置的连接池:先配置连接池  -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///study"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <!-- 配置JDBC的模板类 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

        <!-- 配置平台事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="dao" class="com.mq.dao.MydaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

需要说明的是,Dao类必须在xml文件中配置。其他类的IoC可以使用注解形式

Dao类

public class MydaoImpl extends JdbcDaoSupport implements Mydao {

    public void save() {
    System.out.println("这里是持久层");
    }

    //付款
    @Override
    public void pay(String out,int count) {
        this.getJdbcTemplate().update("update t_account set money = money - ? where name = ?", count,out);

    }
    //收到钱
    @Override
    public void receive(String in,int count) {
        this.getJdbcTemplate().update("update t_account set money = money + ? where name = ?", count,in);

    }

}

MydaoImpl 需要继承JdbcDaoSupport 类。从配置文件中可以看出JdbcDaoSupport 有一个dataSource的属性,该属性需要注入连接池
因此,MydaoImpl在xml文件中配置IoC,没有使用注解的IoC

serevice类

@Transactional
@Component(value="myService")
public class MyServiceImpl implements MyService {
    @Resource(name="dao")
    private Mydao mydao;

    @Override
    public void saveUser() {
        System.out.println("业务层保存用户");
    }
    @Override
    public void transfer(String out,String in,int money) {
        mydao.pay(out,money);
        mydao.receive(in,money);
    }

}

需要给MyServiecImpl类添加一个注解:@Transactional,该注解表示该类中的所有方法都开启了事务

测试:

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration("classpath:applicationContext_tx.xml") 
public class MyTest2 {
    @Resource(name="myService")
    private MyService myService;

    @Test
    public void test1() {
        myService.transfer("关羽","张飞",10);

    }
}

数据库操作结果:
数据库操作结果

模拟转账过程中发生异常:

    @Override
    public void transfer(String out,String in,int money) {
        mydao.pay(out,money);
        int i=1/0;
        mydao.receive(in,money);
    }

如果没有开启事务,结果是这样的:
这里写图片描述
可见,关羽的账户少了10元,而张飞的账户并没有收到钱。(初始关羽账户有970,张飞有1030)。

而添加事务的注解后,一旦转账过程中发生异常,那么操作会全部失败。每个人的账户中的钱都保持不变。

版权声明:本文为博主原创文章,未经博主允许不得转载。

【Spring】在Spring框架下使用注解配置JDBC事务

算是对Spring的一个阶段性总结吧,注解、依赖注入、JDBC、事务等重点基本都涉及到了,值得记录一下。 首先是最重要的xml配置文件。虽然使用了注解方式,不过还是需要在XML中设置一些东西...
  • Spixii
  • Spixii
  • 2016年12月22日 19:25
  • 1897

Spring事务管理的五种方式

学习Spring,感觉还是有点不懂,学习事务管理配置这一块,找了一份文档记录一下,不知道对不对,先学着。...
  • young_kim1
  • young_kim1
  • 2015年07月19日 17:35
  • 1404

Spring的四种事务管理(一种编程式事务+三种声明事务)<学习随笔>

Spring的4种事务管理(1种编程式事务+三种声明事务) 一、Spring事务的介绍 二、编程式事务xml的配置 ...
  • liuwenbiao1203
  • liuwenbiao1203
  • 2016年09月05日 14:18
  • 6825

《Spring 2.0技术手册》 读书笔记七-Spring的DAO框架(3)-JDBC事务管理

Spring提供了编程式事务管理(programmatic transaction management)与声明式事务管理(declarative transaction management)。由于...
  • whuqin
  • whuqin
  • 2011年03月13日 20:46
  • 1276

Spring.NET学习笔记16——事务管理Demo源码

  • 2009年11月16日 20:39
  • 2.1MB
  • 下载

Spring框架的第三天(AOP注解方式、JDBC模板、事务管理)

Spring框架的第三天今天内容1. Spring框架的AOP之注解的方式 2. Spring框架的JDBC模板 3. Spring框架的事务管理 案例一:使用Spring框架的AOP技术对DAO层的...
  • qq_35638837
  • qq_35638837
  • 2017年11月01日 17:53
  • 92

【11】框架学习—Spring的事务管理、Spring框架的JDBC模板

Spring框架的事务管理、JDBC模板类的使用、AOP技术(注解方式)
  • honhong1024
  • honhong1024
  • 2017年11月15日 13:26
  • 72

【Spring实战】—— 16 基于JDBC持久化的事务管理

前面讲解了基于JDBC驱动的Spring的持久化管理,本篇开始则着重介绍下与事务相关的操作。 通过本文你可以了解到:   1 Spring 事务管理的机制   2 基于JDBC持久化...
  • mingtianhaiyouwo
  • mingtianhaiyouwo
  • 2016年04月19日 20:26
  • 239

JDBC 学习笔记(四)—— 自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表 - 解无邪

本文目录:       1、自定义JDBC框架 ——数据库元数据:DataBaseMetaData        2、自定义JDBC框架 ——数据库元数据:DataBaseMeta...
  • codepython
  • codepython
  • 2015年01月03日 00:04
  • 850

实例详解Spring JDBC事务管理.doc

  • 2010年10月10日 00:31
  • 66KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Spring笔记(四)——JDBC模板技术和事务管理
举报原因:
原因补充:

(最多只允许输入30个字)