什么是事务?
对数据库的一组连贯的操作,事务具有一些特性,自行百度。
Spring中事务的方式:
代码是在第四讲上修改得到的:
1、基于xml文件的声明式事务。
accountDao:
package com.jdbc;
import java.util.List;
public interface AccountDao {
//添加
public int addAccount(Account account);
//更新
public int updateAccount(Account account);
//根据id删除
public int deleteAccount(Account account);
//通过id查询
public Account findById(int id);
//查询所有账户
public List<Account>findAll();
//转账
public void transfer(String outUser,String inUser,Double money);//增加transfer方法
}
accountDaoImpl类:
package com.jdbc;
import java.util.List;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class AccountDaoImpl implements AccountDao {
//声明JDBCTemplate属性
private JdbcTemplate jdbcTemplate;
//添加
@Override
public int addAccount(Account account) {
// TODO Auto-generated method stub
String sql="insert into account(username,balance) values(?,?)";
Object[] obj=new Object[] {
account.getUsername(),
account.getBalance()
};
//返回条数影响的
return this.jdbcTemplate.update(sql,obj);
}
//更新账户
@Override
public int updateAccount(Account account) {
// TODO Auto-generated method stub
String sql="update account set username=?,balance=? where id=?";
Object[] obj=new Object[] {
account.getUsername(),
account.getBalance(),
account.getId()
};
return this.jdbcTemplate.update(sql,obj);
}
//删除账户
@Override
public int deleteAccount(Account account) {
// TODO Auto-generated method stub
String sql="delete from account where id=?";
return this.jdbcTemplate.update(sql,account.getId());
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public Account findById(int id) {
// TODO Auto-generated method stub
String sql="select * from account where id=?";
//将account与数据库种的account一一对应
RowMapper<Account> rowMapper=new BeanPropertyRowMapper<Account>(Account.class);
return this.jdbcTemplate.queryForObject(sql, rowMapper,id);
}
@Override
public List<Account> findAll() {
String sql="select * from account";
//将account与数据库种的account一一对应
RowMapper<Account> rowMapper=new BeanPropertyRowMapper<Account>(Account.class);
return this.jdbcTemplate.query(sql, rowMapper);
}
@Override
public void transfer(String outUser, String inUser, Double money) {
// TODO Auto-generated method stub
this.jdbcTemplate.update("update account set balance=balance+? "+"where username=?",money,inUser);
int i=1/0;//模拟事务发生突发状况而中断,两条更新操作应该要么都完成要么都不执行,这里来演示是否满足事务的要求。
this.jdbcTemplate.update("update account set balance=balance-? "+"where username=?",money,outUser);
}
}
测试类:
package com.jdbc;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TransactionTest {
@Test
public void xmlTest() {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao=(AccountDao) applicationContext.getBean("accountDao");
accountDao.transfer("tom2", "tom", 100.0);
/*
转账方法先在转出账户扣钱,再到转入账户增加金额,这是一个事务,不能只完成其中的一部。
本例测试后可以去数据库中查看是否在正确。
*/
System.out.println("success");
}
@Test
public void annotationxmlTest() {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext2-annotation.xml");
AccountDao accountDao=(AccountDao) applicationContext.getBean("accountDao");
accountDao.transfer("tom2", "tom", 100.0);
System.out.println("success");
}
}
xml文件:除了基本的bean和数据库源的创建,还需要配置事务属性(属性作用自行百度),和aop切面让spring自动生成代理。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd"><!-- 注明spring版本 -->
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 数据库驱动 -->
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"></property>
<!-- 连接数据库的url -->
<property name="url" value="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=Spring"></property>
<!-- 连接数据库的用户名密码 -->
<property name="username" value="sa"></property>
<property name="password" value="123"></property>
</bean>
<!-- 配置jdbc模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 默认必须使用数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 定义id为accountDao的bean -->
<bean id="accountDao" class="com.jdbc.AccountDaoImpl">
<!-- 将jdbcTemplate 注入到accountDao实例中 -->
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!-- 事务管理器,依赖于数据源 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 编写通知:对事务增强,需要编写对切入点和具体执行事务细节 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 任意方法 -->
<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* com.jdbc.*.*(..))" id="txPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
2、基于注解的声明式事务:
注解只需要改其中的xml文件,把aop和事务声明删了,加上事务管理驱动器。
xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 数据库驱动 -->
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"></property>
<!-- 连接数据库的url -->
<property name="url" value="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=Spring"></property>
<!-- 连接数据库的用户名密码 -->
<property name="username" value="sa"></property>
<property name="password" value="123"></property>
</bean>
<!-- 配置jdbc模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 默认必须使用数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 定义id为accountDao的bean -->
<bean id="accountDao" class="com.jdbc.AccountDaoImpl">
<!-- 将jdbcTemplate 注入到accountDao实例中 -->
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
accounDaoImpl类:
在xml文件没有配置开启注解管理器是因为在xml文件里配置了accounDaoImpl的bean,并且在该类的transfer方法上增加了事务注解。
代码同xml声明式的事务(第二个Junit测试)