Spring框架提供了一个JdbcTemplate模板类。用来创建不同的连接池。

一:连接池的使用

1.首先用new的方式创建一个JDBC模板类

//演示的JDBC的模板类
public class Demo1 {
	 //演示模板类,自己new的方式
	@Test
	public void run1() {
		//1.Spring提供了内置的连接池,也可整合其他连接池
		DriverManagerDataSource dataSource=new DriverManagerDataSource();
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql:///spring_JDBC");
		dataSource.setUsername("root");
		dataSource.setPassword("root");
		//2. 创建模板类
		JdbcTemplate template=new JdbcTemplate();
		template.setDataSource(dataSource);

		template.update("insert into t_account values (null,?,?)","xxx",1000);
	}
}

执行以下语句成功将数据插入到数据库表中。

2.用IOC配置容器的方式

第一个配置注入方式参考new的形式,dataSource有set方法,那么就可以在配置文件中直接配置相应的属性值。

而第二天模板类中需要传入一个dataSource 参数,所以需要在jdbcTemplate模板类中配置一个dataSource的属性。而dataSource是一个具体的类,所以不能用value关键字,而需要用ref关键字。

<!-- 先配置连接池 -->
<bean id="dataSource"
	class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName"value="com.mysql.jdbc.Driver"></property>
	<property name="url" value="jdbc:mysql:///spring_day03"></property>
	<property name="username" value="root"></property>
	<property name="password" value="root"></property>
</bean>
<!-- 配置JDBC模板类 -->
<bean id="jdbcTemplate"
	class="org.springframework.jdbc.core.JdbcTemplate">
	<!-- 模板类需要一个连接池,就注入一个,与new的方式差不多 -->
	<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 完成以上两个的注入,跟new方式的1,2一样 -->

3.DBCP连接池的容器配置

<!-- 配置DBCP的连接池 -->
<bean id="dataSource"
	class="org.apache.commons.dbcp.BasicDataSource">
	<property name="driverClassName"value="com.mysql.jdbc.Driver"></property>
	<property name="url" value="jdbc:mysql:///spring_day03"></property>
	<property name="username" value="root"></property>
	<property name="password" value="root"></property>
</bean>
<!-- 配置JDBC模板类 -->
<bean id="jdbcTemplate"
	class="org.springframework.jdbc.core.JdbcTemplate">
	<!-- 模板类需要一个连接池,就注入一个,与new的方式差不多 -->
	<property name="dataSource" ref="dataSource"></property>
</bean>

4.C3P0连接池的容器配置

<!-- 配置DBCP的连接池 -->
<bean id="dataSource"
	class="com.mchange.v2.c3p0.ComboPooledDataSource">
	<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
	<property name="jdbcUrl" value="jdbc:mysql:///spring_day03"></property>
	<property name="user" value="root"></property>
	<property name="password" value="root"></property>
</bean>
<!-- 配置JDBC模板类 -->
<bean id="jdbcTemplate"
	class="org.springframework.jdbc.core.JdbcTemplate">
	<!-- 模板类需要一个连接池,就注入一个,与new的方式差不多 -->
	<property name="dataSource" ref="dataSource"></property>
</bean>

以上连接池的方式都大同小异。C3P0稍微需要修改下。

二:事务的使用

  1. 事务:指的是逻辑上的一组操作,组成这个事务的各个执行单元,只有一起成功或一起失败。
  2. 事务的特性
    1. 原子性
    2. 一致性
    3. 隔离性
    4. 持久性
  3. 如果不考虑隔离性,引发安全性问题
    1. 读问题
      1. 脏读
      2. 不可重复读
      3. 虚读
    2. 写问题
  4. 如何解决安全性问题
    1. 读问题解决,设置数据库的隔离级别
    2. 写问题解决可以使用 悲观锁和乐观锁的方式解决

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

  • PlatformTransactionManager接口  ---平台事务管理器(管理事务的类)。该接口有具体的实现类,根据不同持久层框架,需要不同实现类
  • TransactionDefinition接口               ---事务定义信息(事务的隔离级别,传播行为,超时,只读)
  • TransactionStatus接口                    ---事务的状态

首先创建Service类和Dao类。Dao类下有加钱和扣钱的方法 ,注:这里直接继承了JdbcDaoSupport,这样就不用写依赖的模板程序了。

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
//下面代码可以不写,直接继承JdbcDaoSupport就可以了,不然每次都需要写依赖太过麻烦
//	private JdbcTemplate JdbcTemplate;
//	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
//		JdbcTemplate = jdbcTemplate;
//	}
	 //扣钱
	@Override
	public void outMoney(String out, double money) {
		//JdbcTemplate.update(psc);//这个也要删掉
		this.getJdbcTemplate().update("update t_account set money=money-? where name=?",money,out);
	}
	 //加钱
	@Override
	public void inMoney(String in, double money) {
		this.getJdbcTemplate().update("update t_account set money=money+? where name=?",money,in);
	}
}

容器配置如下,注:这里Dao层可以不用注入模板类,因为Dao类继承了JdbcDaoSupport ,可以直接注入C3P0连接池

<!-- 配置c3p0的连接池 -->
<bean id="dataSource"
	class="com.mchange.v2.c3p0.ComboPooledDataSource">
	<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
	<property name="jdbcUrl" value="jdbc:mysql:///spring_day03"></property>
	<property name="user" value="root"></property>
	<property name="password" value="root"></property>
</bean>
<!-- 配置JDBC模板类 -->
<bean id="jdbcTemplate"
	class="org.springframework.jdbc.core.JdbcTemplate">
	<!-- 模板类需要一个连接池,就注入一个,与new的方式差不多 -->
	<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置业务层和持久层 -->
<bean id="accountService" class="com.affair.AccountServiceImpl">
	<property name="accountDao" ref="accountDao"></property>
</bean>
<bean id="accountDao" class="com.affair.AccountDaoImpl">
	<!-- Dao里面注入了模板类 -->
	<!--<property name="jdbcTemplate" ref="jdbcTemplate"></property>  -->
	<!--  <property name="jdbcTemplate" ref="jdbcTemplate"></property>-->
	<!-- 模板类可以直接注释了  这里我们注入模板可以,注入连接池也OK -->
	<property name="dataSource" ref="dataSource"></property>
</bean>

以上基本的环境写好了,接下来配置事务。容器添加如下:pay方法是service层的方法

<!-- 配置平台事务管理器 -->
<bean id="transactionManager"
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 声明式事务(采用XML配置文件的方式) -->
<!-- 先配置通知 -->   <!-- 传入事务管理器 -->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<!-- 当执行到pay方法的时候,设置一些传播行为等.. -->
		<tx:method name="pay" propagation="REQUIRED" />
	</tx:attributes>
</tx:advice>
<!-- 配置AOP 如果是自己编写的AOP,使用aop:aspect配置,使用Spring框架提供的通知用aop:advisor 当执行到某个方法时 -->
<aop:config>
	<!-- aop:advisor,是Spring框架提供的通知 -->
	<aop:advisor advice-ref="myAdvice" pointcut="execution(public * com.affair.AccountServiceImpl.pay(..))" />
</aop:config>

接下来在service层模拟异常,代码如下:

public class AccountServiceImpl implements AccountService{
	private AccountDao accountDao;
	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}
	 //转账的方法
	public void pay(String out, String in, double money) {
		//先扣钱
		accountDao.outMoney(out, money);
		//模拟异常
		int i=1/0;
		//再加钱
		accountDao.inMoney(in, money);
	}
}

执行测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContextAffair.xml")
public class Demo1 {
	@Resource(name="accountService")
	private AccountService accountService;
	@Test
	public void run1() {
		//调用支付的方法
		accountService.pay("xu", "wuwu", 200);
	}
}

从结果可以看出JUnit报异常,但是数据库并没有发生变化,事务模拟成功!

以上就是通过配置文件的方式来管理事务。

还可以通过注解的方式,更加简单,下面看代码。

在容器配置里面只要加入这一行。 开启事物的注解形式。

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

然后在需要加入事务的类上,或者类的方法中加入@Transactional 即可。

@Transactional
public class AccountServiceImpl implements AccountService{
	private AccountDao accountDao;
	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}
	 //转账的方法
	public void pay(String out, String in, double money) {
		//先扣钱
		accountDao.outMoney(out, money);
		//模拟异常
		int i=1/0;
		//再加钱
		accountDao.inMoney(in, money);
	}
}

同样测试成功!!!

01-30 17:05