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稍微需要修改下。
二:事务的使用
- 事务:指的是逻辑上的一组操作,组成这个事务的各个执行单元,只有一起成功或一起失败。
- 事务的特性
- 原子性
- 一致性
- 隔离性
- 持久性
- 如果不考虑隔离性,引发安全性问题
- 读问题
- 脏读
- 不可重复读
- 虚读
- 写问题
- 读问题
- 如何解决安全性问题
- 读问题解决,设置数据库的隔离级别
- 写问题解决可以使用 悲观锁和乐观锁的方式解决
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);
}
}
同样测试成功!!!