一、连接池的配置交给Spring管理
1,添加jar包
2,spring的jdbc连接池配置
<!-- 配置连接池 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="password" value="tianyejun" />
<property name="username" value="root" />
<property name="url" value="jdbc:mysql:///springday3" />
</bean>
<!-- 配置jdbc的模板类 -->
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
3,测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
/**
* 使用ioc的方式
*/
@Resource(name = "JdbcTemplate")
private JdbcTemplate JdbcTemplate;
@Test
public void run2() {
// 可以实现对数据库的cud
JdbcTemplate.update("insert into t_account values(null,?,?)", "3343", "1000");
}
/**
* 数据库查询
*/
@Test
public void runQuery() {
//查询一条数据
AccontBean bean =JdbcTemplate.queryForObject("select * from t_account where id=?", new String[] { "1" },
new MyrowMapper());
System.out.println(bean.toString());
// 查询所有数据
List<AccontBean> list = (List<AccontBean>) JdbcTemplate.query("select * from t_account",new MyrowMapper());
System.out.println(list);
}
public class MyrowMapper implements RowMapper<AccontBean> {
@Override
public AccontBean mapRow(ResultSet rs, int rowNum) throws SQLException {
AccontBean bean = new AccontBean();
bean.setName(rs.getString(2));
bean.setPrice(rs.getInt(3));
return bean;
}
}
}
}
二、Spring的事物管理
1,事物的特性
原子性 :强调事务的不可分割.
一致性 :事务的执行的前后数据的完整性保持一致.
隔离性 :一个事务执行的过程中,不应该受到其他事务的干扰
持久性 :事务一旦结束,数据就持久到数据库
2,事物的传播行为
PROPAGION_XXX :事务的传播行为
- 保证同一个事务中
PROPAGATION_REQUIRED:支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_SUPPORTS:支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY:支持当前事务,如果不存在,抛出异常
- 保证没有在同一个事务中
PROPAGATION_REQUIRES_NEW: 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED :以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER : 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED: 如果当前事务存在,则嵌套事务执行
案例:模拟银行转账漏洞环境
(1)创建业务层
业务层接口类:
public interface AccountServiceInter {
public void pay(String out, String in, double money);
}
业务层接口实现类
public class AccountServiceImp implements AccountServiceInter {
private AccountDaoInter acountdao;
/**
* 转账的方法
*/
@Override
public void pay(String out, String in, double money) {
// 先价钱
getAcountdao().outMoney(out, money);
/**
*这里人为制造一个异常,造成转账出现异常
*/
int a=10/0;
// 后加钱
getAcountdao().inMoney(in, money);
}
public AccountDaoInter getAcountdao() {
return acountdao;
}
public void setAcountdao(AccountDaoInter acountdao) {
this.acountdao = acountdao;
}
}
(2)创建dao层
dao接口类
public interface AccountDaoInter {
// 扣钱
public void outMoney(String out, double money);
// 加钱
public void inMoney(String in, double money);
}
dao接口实现类
public class AccountDaoImp extends JdbcDaoSupport implements AccountDaoInter {
/**
* 扣钱
*/
@Override
public void outMoney(String out, double money) {
int update = this.getJdbcTemplate().update("update t_account set money=(money-?) where id=?", money, out);
System.out.println("fdafd" + update);
}
/**
* 加钱
*/
@Override
public void inMoney(String in, double money) {
int update = this.getJdbcTemplate().update("update t_account set money=(money+?) where id=?", money, in);
System.out.println("fdafd" + update);
}
}
(3)spring中配置业务层和dao
<!-- 配置连接池 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="password" value="tianyejun6" />
<property name="username" value="root" />
<property name="url" value="jdbc:mysql:///springday3" />
</bean>
<!-- service业务层 -->
<bean id="accountService" class="com.itcast.test1.AccountServiceImp">
<property name="acountdao" ref="accountDaoImp"></property>
</bean>
<!-- 持久层dao -->
<bean id="accountDaoImp" class="com.itcast.test1.AccountDaoImp">
<property name="dataSource" ref="dataSource" />
</bean>
(4)编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test1 {
@Resource(name = "accountService")
private AccountServiceInter accountService;
DataSourceTransactionManager a;
@Test
public void run1() {
accountService.pay("1", "3", 100);
}
}
总结:上面转账过程如果出现异常情况,就会造成转账漏洞,所以采用下面AOP转账方式
三、spring事务管理采用AOP方式
1,引入jar包
2,配置事务管理器 ,开启事物注解
<!-- 1,配置平台事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启注解事务管理 -->
<tx:annotation-driven
transaction-manager="transactionManager"/>
3,配置事务的通知
<!-- 2,配置通知 -->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
isolation="DEFAULT" 隔离级别
propagation="REQUIRED" 传播行为
read-only="false" 只读
timeout="-1" 过期时间
rollback-for="" -Exception
no-rollback-for="" +Exception
-->
<tx:method name="pay" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
4,配置AOP
<!--
配置AOP:如果是自己编写的aop使用<aop:aspect>;
如果使用spring框架提供的通知使用<aop:advisor/>
-->
<aop:config>
<aop:advisor advice-ref="myAdvice"
pointcut="execution(public * com.itcast.test2.AccountServiceImp.pay(..))"/>
</aop:config>
5,实现代码
(1)业务层
业务层接口
public interface AccountServiceInter {
public void pay(String out, String in, double money);
}
业务层接口实现类
/**
*
*@Transactional 添加到类上,该类所有的方法都有事务
*/
@Transactional
public class AccountServiceImp implements AccountServiceInter {
private AccountDaoInter acountdao;
/**
* 转账的方法
*/
@Override
@Transactional
public void pay(String out, String in, double money) {
// 先价钱
getAcountdao().outMoney(out, money);
// int a=10/0;
// 后加钱
getAcountdao().inMoney(in, money);
}
public AccountDaoInter getAcountdao() {
return acountdao;
}
public void setAcountdao(AccountDaoInter acountdao) {
this.acountdao = acountdao;
}
}
(2)dao层
dao接口类
public interface AccountDaoInter {
// 扣钱
public void outMoney(String out, double money);
// 加钱
public void inMoney(String in, double money);
}
dao实现接口类
public class AccountDaoImp extends JdbcDaoSupport implements AccountDaoInter {
/**
* 扣钱
*/
@Override
public void outMoney(String out, double money) {
int update = this.getJdbcTemplate().update
("update t_account set money=(money-?) where id=?", money, out);
System.out.println("fdafd" + update);
}
/**
* 加钱
*/
@Override
public void inMoney(String in, double money) {
update("update t_account set money=(money+?) where id=?", money, in);
System.out.println("fdafd" + update);
}
}
(3)Spring的xml配置
<!-- 配置连接池 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="password" value="tianyejun6" />
<property name="username" value="root" />
<property name="url" value="jdbc:mysql:///springday3" />
</bean>
<!-- service业务层 -->
<bean id="accountService" class="com.itcast.test2.AccountServiceImp">
<property name="acountdao" ref="accountDaoImp"></property>
</bean>
<!-- 持久层dao -->
<bean id="accountDaoImp" class="com.itcast.test2.AccountDaoImp">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 1,配置平台事物管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 声明式事物 -->
<!-- 2,配置通知 -->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="pay" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!--
配置AOP:如果是自己编写的aop使用<aop:aspect>;
如果使用spring框架提供的通知使用<aop:advisor/>
-->
<aop:config>
<aop:advisor advice-ref="myAdvice"
pointcut="execution(public * com.itcast.test2.AccountServiceImp.pay(..))"/>
</aop:config>
(4)测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class Test1 {
@Resource(name = "accountService")
private AccountServiceInter accountService;
DataSourceTransactionManager a;
@Test
public void run1() {
accountService.pay("1", "3", 100);
}
}
(5)源码