5.JDBC模板与事务处理

一、Spring的JDBC模板的使用1.使用入门需要引入的jar包:基本的jar包:  spring-expression-4.2.4.RELEASE.jar  spring-core-4.2.4.RELEASE.jar  spring-context-4.2.4.RELEASE.jar  spring-beans-4.2.4.RELEASE.jar  spring-test-4....
摘要由CSDN通过智能技术生成

一、Spring的JDBC模板的使用
1.使用入门
需要引入的jar包
基本的jar包:
  spring-expression-4.2.4.RELEASE.jar
  spring-core-4.2.4.RELEASE.jar
  spring-context-4.2.4.RELEASE.jar
  spring-beans-4.2.4.RELEASE.jar
  spring-test-4.2.4.RELEASE.jar
  com.springsource.org.apache.log4j-1.2.15.jar
  com.springsource.org.apache.commons.logging-1.1.1.jar
数据库驱动jar包:
  mysql-connector-java-5.1.7-bin.jar
Spring中JDBC模板的jar包:
  spring-tx-4.2.4.RELEASE.jar
  spring-jdbc-4.2.4.RELEASE.jar

测试代码

public class jdbcdemo1 {
    @Test
    public void demo1() {
    	//创建连接池
    	DriverManagerDataSource datasource = new DriverManagerDataSource();
    	datasource.setDriverClassName("com.mysql.jdbc.Driver");  //驱动类在导入的jar文件中
    	datasource.setUrl("jdbc:mysql:///jdbc_database");  //jdbc_database为所创建的数据库
    	datasource.setUsername("root");
    	datasource.setPassword("2e5y8hxf");
    	
    	//创建jdbc模板
    	JdbcTemplate jdbctemplate = new JdbcTemplate(datasource);
    	jdbctemplate.update("insert into account values(null,'张三丰',10000)");
    }
}

注意:这里"com.mysql.jdbc.Driver"路径是在mysql-connector-java-5.1.7-bin.jar包中的com/mysql/jdbc目录下的Driver.class文件。
终端SQL操作

create database jdbc_database;
use jdbc_database;
mysql> create table account(
     id int primary key auto_increment,
     name varchar(20),
     money double
);

select *from account;

测试结果
在这里插入图片描述

2.将连接池和模板交给Spring管理
导入jar包
需要另外导入spring-aop-4.2.4.RELEASE.jar
配置文件代码

<?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">

    <!-- 配置SPring内置的连接池 -->
    <bean id = "dataSource"  class = "org.springframework.jdbc.datasource.DriverManagerDataSource"> 
        <property name="driverClassName" value = "com.mysql.jdbc.Driver"/>
        <property name="url" value = "jdbc:mysql:///jdbc_database"/>
        <property name="username" value = "root"/>
        <property name="password" value = "2e5y8hxf"/>        
    </bean>
    
    <!-- 配置Spring的JDBC模板 -->
    <bean id = "jdbctemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref = "dataSource"/>
    </bean>

</beans>

注意的问题:注意配置文件要建在src文件下,不能建在包下。
测试代码

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:jdbc_first.xml")
public class jdbcdemo1 {
	@Resource(name="jdbctemplate")
	private JdbcTemplate jdbctemplate;
	
    @Test
    public void demo1() {
         jdbctemplate.update("insert into account values(null,?,?)","张无忌",100000);
    }
}

3.DBCP连接池的配置
导入jar包
com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
com.springsource.org.apache.commons.pool-1.5.3.jar
配置文件代码
将2.中连接池部分配置代码替换为DPCP连接池部分代码即可

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

4.C3P0连接池的配置
导入jar包
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
配置文件代码

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

5.引入外部属性文件
建立属性文件:txt文件,包含以下内容
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///jdbc_database
jdbc.username=root
jdbc.password=2e5y8hxf

引入属性文件的两种方式

    <!-- 第一种方式:通过bean标签引入(使用较少) -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:jdbc.properties"/>
    </bean>

    <!-- 第二种方式:通过context标签引入-->     
    <context:property-placeholder location="classpath:jdbc.properties"/> 

    <!-- 修改连接池:配置C3P0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value = "${jdbc.driverClass}"/>
        <property name="jdbcUrl" value = "${jdbc.url}"/>
        <property name="user" value = "${jdbc.username}"/>
        <property name="password" value = "${jdbc.password}"/>        
    </bean>

6.进行增删改查的操作

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:jdbc_first.xml")
public class jdbcdemo1 {
	@Resource(name="jdbctemplate")
	private JdbcTemplate jdbctemplate;
	
    @Test
    //添加一列数据
    public void demo1() {
         jdbctemplate.update("insert into account values(null,?,?)","杨过",100000);
    }
    
    @Test
    //修改id为3的一列数据
    public void demo2() {
         jdbctemplate.update("update account set name = ? ,money = ? where id = ?","任我行",999999,3);
    }
    
    @Test
    //删除id为2的一列数据
    public void demo3() {
         jdbctemplate.update("delete from account where id = ?",2);
    }
    
    @Test
    //查询id为1的name数据
    public void demo4() {
         String abc = jdbctemplate.queryForObject("select name from account where id = ?", String.class,1);
         System.out.println(abc);
         //格式:jdbctemplate.queryForObject(sql, rowMapper, args);
    }
    
    @Test
    //对查询结果进行数值统计
    public void demo5() {
         Long count = jdbctemplate.queryForObject("select count(*) from account", Long.class);
         System.out.println(count);
         //格式:jdbctemplate.queryForObject(sql, requiredType)
    }
    
    @Test
    //将查询到的结果封装到一个对象中
    public void demo6() {
         Account account = jdbctemplate.queryForObject("select *from account where id = ?", new MyRowMapper(),8);
         System.out.println(account);
         //格式:jdbctemplate.queryForObject(sql, requiredType)
    }
    
    @Test
    //查询多条记录
    public void demo7() {
         List<Account> list = jdbctemplate.query("select *from account", new MyRowMapper());
         for(Account account:list) {
        	 System.out.println(account); 
         }
             

    }
    
    class MyRowMapper implements RowMapper<Account>{

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

二、Spring的事务处理
1.事务管理概述
事务管理详解:转自:https://www.cnblogs.com/yixianyixian/p/8372832.html
什么是事务
事务:逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。
举例:取钱。
  比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱;然后ATM出1000元钱。这两个步骤必须是要么都执行要么都不执行。如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元;如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元。所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的。
  事务就是用来解决类似问题的。事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。
  在企业级应用程序开发中,事务管理必不可少的技术,用来确保数据的完整性和一致性。

事务的特性
原子性:事务不可分割;
一致性:事务执行前后,数据完整性保持一致;
隔离性:一个事务的执行不应该受到其他事务的干扰;
持久性:一旦事务结束,数据就持续化到数据库。

如果不考虑隔离性应发的安全性问题
读问题:
  脏读:一个事务读到另一个事务未提交的数据;
  不可重复读:一个事务读到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致;
  虚读、幻读:一个事务读到另一个事务已经提交的insert的数据,导致一个事务中多次查询结果不一致;
  
写问题:
  丢失更新

解决读问题
设置事务的隔离级别:
  Read uncommitted:未提交读,任何读问题解决不了;
  Read committed:已提交读,解决脏读,但是不可重复读,并且虚读有可能发生;
  Repeatable read:重复读,解决脏读和不可重复读,但是虚读有可能发生;
  Serializable:解决所有读问题(效率较低)。

2.Spring的事务管理API
PlatformTransactionManager:平台事务管理器,这是一个接口,是Spring用于管理事务的真正的对象,其具体实现类如下:
  DataSourceTransactionManager :底层使用JDBC管理事务;
  HibernateTransactionManager :底层使用Hibernate管理事务;

TransactionDefinition:事务定义信息,用于定义事务相关的信息,隔离级别、超时信息、传播行为、是否只读。

TransactionStatus:事务的状态,用于记录在事务管理过程中,事务的状态的对象。

事务管理API之间的关系:Spring进行事务管理的时候,首先,平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中产生各种状态,将这些状态的信息记录到事务的状态的对象中。

3.Spring的事务传播行为
事务传播行为解决的问题:如果遇到了特别复杂的业务逻辑,有可能出现业务层之间的方法相互调用,事务传播就是解决业务层方法相互调用的问题。

举例:如下图所示,是一个业务层之间方法相互调用的情况
在这里插入图片描述
Spring中提供了7中事务传播行为:
保证多个操作在同一事务中
PROPAGATION_REQUIRED :默认值,如果X中有事务,使用X中的事务,如果X中没有事务,则创建一个新的事务,将操作(即X()、c()、d()三个操作)包含进来。
PROPAGATION_SUPPORTS :支持事务,如果X中有事务,则使用X中的事务;如果X中没有事务,则不使用事务。
PROPAGATION_MANDATORY:如果X中有事务,则使用X中的事务;如果X中没有事务,则抛出异常。
保证多个操作不再同一个事务中
PROPAGATION_REQUIRES_NEW:如果X中有事务,将X中的事务挂起(暂停),并创建新事务,只包含自身操作(即c、d);如果X中没有事务,也创建一个新事务,包含自身操作。
PROPAGATION_NOT_SUPPORTED:如果X中有事务,将X中的事务挂起,不使用事务管理。
PROPAGATION_NEVER:如果A中有事务,报异常。
嵌套式事务
PROPAGATION_NESTED:嵌套事务,如果X中有事务,按照X中的事务执行,执行完后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。

4.搭建Spring事务管理环境
步骤
创建Service接口和实现类、
创建DAO接口和实现类、
配置Service和DAO将其交给Spring管理

代码:
Service和DAO接口和实现类

public interface AccountService {
    public void transfer(String from,String to,double money);
}


public class AccountServiceImpl implements AccountService{
    private AccountDao accountDao;
    
	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}
	/*
	 * from:转出账户
	 * to:转入账户
	 * money:金额
	 * */
	@Override
	public void transfer(String from, String to, double money) {
		accountDao.outMoney(from, money);
		accountDao.inMoney(to, money);
	}
}



public interface AccountDao {
    public void outMoney(String from,double money);
    public void inMoney(String to, double money);
}


public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
	/*	这里继承了JdbcDaoSupport之后,就不需要使用这部分代码了,因为JdbcDaoSupport 里包含get与set方法
    private JdbcTemplate jdbcTemplate;
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}
*/
	@Override
	public void outMoney(String from,double money) {
		this.getJdbcTemplate().update("update account set money = money - ? where name = ?",money,from);
		
	}
	@Override
	public void inMoney(String to,double money) {
		this.getJdbcTemplate().update("update account set money = money + ? where name = ?",money,to);
	}

}

配置文件代码

<?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">

    <!-- 配置Service -->
    <bean id = "accountService" class = "package2.AccountServiceImpl">
        <property name="accountDao" ref = "accountDao"/>
    </bean>
    
    <!-- 配置DAO -->
    <bean id = "accountDao" class = "package2.AccountDaoImpl">
        <property name="jdbcTemplate" ref = "jdbcTemplate"/>
    </bean>
     
    <context:property-placeholder location="classpath:jdbc.properties"/> 
    
    <!-- 配置C3P0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value = "${jdbc.driverClass}"/>
        <property name="jdbcUrl" value = "${jdbc.url}"/>
        <property name="user" value = "${jdbc.username}"/>
        <property name="password" value = "${jdbc.password}"/>        
    </bean>
    
    <!-- 配置Spring的JDBC模板(这一步可以通过一些操作省略) -->
    <bean id = "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref = "dataSource"/>
    </bean>

</beans>

测试类代码

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:tx.xml")
public class spring_demo1 {
	@Resource(name = "accountService")
	private AccountService accountService;
	
    @Test
    public void demo1() {
    	accountService.transfer("张三丰", "张无忌", 500);
    }
}

测试结果:张三丰给张无忌转了500块钱
在这里插入图片描述

5.编程式事务管理(需要写代码)
第一步:配置平台事务管理器

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

第二步:配置事务管理的模板类

    <!-- 配置事务管理的模板 -->
    <bean id = "transactionTemplate" class = "org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref = "transactionManager"/>
    </bean>

第三步:在业务层注入事务管理的模板

    <!-- 配置Service -->
    <bean id = "accountService" class = "package2.AccountServiceImpl">
        <property name="accountDao" ref = "accountDao"/>
        <!-- 注入事务管理的模板 -->
        <property name="transactionTemplate" ref = "transactionTemplate"/>
    </bean>

同时在AccountServiceImpl类中添加如下代码:

	//注入事务管理的模板
	private TransactionTemplate transactionTemplate;
	 
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}

第四步:编写事务管理的代码
在AccountServiceImpl实现类中修改成如下代码:

@Override
	public void transfer(String from, String to, double money) {
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {

			@Override
			protected void doInTransactionWithoutResult(TransactionStatus arg0) {
				accountDao.outMoney(from, money);
				int a = 1/0;
				accountDao.inMoney(to, money);
			}	
		});


	}

6.声明式事务管理(不需要修改代码)
声明式事务管理有两种实现方式:XML方式和注解方式

XML方式:
第一步:搭建事务管理环境(如:4.搭建Spring事务管理环境);
第二步:引入AOP的开发包
spring-aop-4.2.4.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
org.apache.servicemix.bundles.aopalliance-1.0-1.0.0-rc1.jar
第三步:添加配置文件代码:在(4.搭建Spring事务管理环境)中的配置文件添加如下代码,

    <!-- 配置平台事务管理器 -->
    <bean id = "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref = "dataSource"/>
    </bean>
    
    <!-- 配置事务的增强 -->
    <tx:advice id = "txAdvice" transaction-manager = "transactionManager">
        <tx:attributes>
            <tx:method name="transfer" propagation = "REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- AOP配置 -->
    <aop:config>
        <aop:pointcut expression="execution(* package3.AccountServiceImpl.*(..))" id="pointcut1"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref = "pointcut1"/>
    </aop:config>

注解方式:
第一步:搭建事务管理环境(如:4.搭建Spring事务管理环境);
第二步:引入AOP的开发包
第三步:添加配置文件代码

    <!-- 配置平台事务管理器 -->
    <bean id = "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref = "dataSource"/>
    </bean>
    
    <!-- 开启注解事务 -->
    <tx:annotation-driven transaction-manager = "transactionManager"/>

第四步:在业务层添加注解
在这里插入图片描述

结果分析:在进行XML或者注解方式的声明事务管理后,出现异常,则“扣钱”与“收款”操作都不能执行了,从而实现了事务管理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值