前提介绍:通过上一张我们通过对手动事务的控制,达到语句错误而进行回滚 https://blog.csdn.net/weixin_46809332/article/details/115746945,而spring提供了事务的控制。
一:介绍
1. spring提供了分层涉及业务层的事务处理解决方案,提供了一组事务控制的接口,并且事务控制都是基于aop的。
2. api介绍
–2.1 PlatformTransactionManager接口提供事务操作的方法
获取事务状态信息 TransactionStatus getTransaction(TransactionDefinition definition)
提交事务 void commit(TransactionStatus status)
回滚事务 void rollback(TransactionStatus status)
真正管理事务的对象 org.springframework.jdbc.datasource.DataSourceTransactionManager 使用 Spring JDBC 或 iBatis 进行持久化数据时使用
org.springframework.orm.hibernate5.HibernateTransactionManager 使用 Hibernate 版本进行持久化数据时使用
– 2.2 TransactionDefinition
获取事务对象的名称 String getName();
获取事务的隔离级 int getIsolationLevel();
获取事务传播行为 int getPropagationBehavior();
获取事务超时时间 int getTimeout()
获取事务是否只读 boolean isReadOnly()
读写型事务:修改、删除、增加开启事务 只读型事务:执行查询时,也会开启事务
---- 事务的隔离级别
- --事务的传播行为
—超时时间
默认值是-1,没有超时限制,如果有,以秒为单位进行设置
– 2.3TransactionStatus
3. xml代码实现
spring中基于xml的声明事务控制步骤
– 1配置事务管理器
–2配置事务的通知
–3配置aop中通用切入点表达式
–4 建立事务通知和切入点表达式的对应关系
–5配置事务的属性
3.1 结构图
3.1导入pom.xml
<artifactId>spring-jdbc</artifactId>
<artifactId>spring-context</artifactId>'
<artifactId>spring-tx</artifactId>
<artifactId>aspectjweaver</artifactId>
<artifactId>mysql-connector-java</artifactId>
<artifactId>junit</artifactId>
<artifactId>log4j</artifactId>
3.2 . 实体类account
3.3 service
public class IaccountServiceImpl implements IaccountService
{
private IaccountDao accDao;
public void setAccDao(IaccountDao accDao) {
this.accDao = accDao;
}
public List<account> findAll() throws SQLException {
return accDao.findAll();
}
public account findById(Integer id) throws SQLException {
return accDao.findById(id);
}
public void updateAcc(account acc) throws SQLException {
accDao.updateAcc(acc);
}
public void deleteById(Integer id) throws SQLException {
accDao.deleteById(id);
}
public void insert(account acc) throws SQLException {
accDao.insert(acc);
}
public void transfer(String sourceName, String targetName, float money) throws SQLException {
//执行操作
//获取转账人的钱数
account aa = accDao.findByNme(sourceName);
account bb = accDao.findByNme(targetName);
//转账
aa.setMoney(aa.getMoney()-money);
bb.setMoney(bb.getMoney()+money);
//更新
accDao.updateAcc(aa);
//int a=1/0;
accDao.updateAcc(bb);
}
}
3.4 dao
public class IaccountDaoImpl extends jdbcDaoSupport implements IaccountDao {
public List<account> findAll() {
List<account> one= getJdbcTemplate().query("select *from account",new AccountRowMapper());
return one;
}
public account findById(Integer id) {
List<account> account = getJdbcTemplate().query("select *from account where id = ?", new AccountRowMapper(), id);
return account.isEmpty()?null:account.get(0);
}
public account findByNme(String name){
List<account> account = getJdbcTemplate().query("select *from account where name = ?", new AccountRowMapper(), name);
if (account.isEmpty()){
return null;
}
if (account.size()>1){
throw new RuntimeException("结果集不唯一。");
}
return account.get(0);
}
public void insert(account account) {
getJdbcTemplate().update("insert into account values(NULL ,?,?)",account.getName(),account.getMoney());
}
public void deleteById(Integer id) {
getJdbcTemplate().update("delete from account whew id = ?",id);
}
public void updateAcc(account account) {
getJdbcTemplate().update("update account set name =? ,money =? where id =? ",account.getName(),account.getMoney(),account.getId());
}
protected void checkDaoConfig() throws IllegalArgumentException {
}
}
3.5 config 这个template主要是通过spring内置的来创建
public class AccountRowMapper implements RowMapper<account> {
public account mapRow(ResultSet resultSet, int i) throws SQLException {
account account = new account();
account.setId(resultSet.getInt("id"));
account.setName(resultSet.getString("name"));
account.setMoney(resultSet.getFloat("money"));
return account;
}
}
public abstract class jdbcDaoSupport extends DaoSupport {
private JdbcTemplate jdbcTemplate;
//set 方法注入数据源,判断是否注入了,注入了就创建 JdbcTemplate
public final void setDataSourc(DataSource dataSourc) {
if (jdbcTemplate==null||dataSourc!=jdbcTemplate.getDataSource()){
this.jdbcTemplate=createJdbcTemplate(dataSourc);
}
}
//使用数据源注入jdbcTemplate
protected JdbcTemplate createJdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource); }
//
// //也可以通过注入JdbcTemplate对象
// public final void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
// this.jdbcTemplate = jdbcTemplate;
// // initTemplateConfig();
// }
3.6bean.xm
<!--配置service-->
<bean id="accountService" class="lml.service.IaccountServiceImpl">
<property name="accDao" ref="accountDao"></property>
</bean>
<!--配置dao-->
<bean id="accountDao" class="lml.dao.IaccountDaoImpl">
<property name="dataSourc" ref="dataSource"></property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/springOne?serverTimezone=UTC"></property>
<property name="username" value="root"></property>
<property name="password" value="admin"></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>
<!-- 指定方法名称:是业务核心方法
read-only:是否是只读事务。默认 false,不只读。
isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。
propagation:指定事务的传播行为。
timeout:指定超时时间。默认值为:-1。永不超时。
rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。
没有默认值,任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回 滚。
没有默认值,任何异常都回滚。
-->
<tx:method name="transfer" read-only="false" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!--配置aop切入点-->
<aop:config>
<aop:pointcut id="pt1" expression="execution(* lml.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
</aop:config>
<aop:aspectj-autoproxy proxy-target-class="true"/>
3.7test
public class test {
@Test
public void one() throws SQLException {
ClassPathXmlApplicationContext co = new ClassPathXmlApplicationContext("bean.xml");
IaccountServiceImpl a = co.getBean("accountService",IaccountServiceImpl.class);
a.transfer("aa","bb",100f);
}
}
4.基于注解的代码实现
不变的是pom.xml pojo下的account
结构图
4.1 service
4.2 dao
@Component("accDao")
public class IaccountDaoImpl implements IaccountDao {
@Autowired
private JdbcTemplate template;
public List<account> findAll() {
List<account> one= template.query("select *from account",new AccountRowMapper());
return one;
}
public account findById(Integer id) {
List<account> account = template.query("select *from account where id = ?", new AccountRowMapper(), id);
return account.isEmpty()?null:account.get(0);
}
public account findByNme(String name){
List<account> account = template.query("select *from account where name = ?", new AccountRowMapper(), name);
if (account.isEmpty()){
return null;
}
if (account.size()>1){
throw new RuntimeException("结果集不唯一。");
}
return account.get(0);
}
public void insert(account account) {
template.update("insert into account values(NULL ,?,?)",account.getName(),account.getMoney());
}
public void deleteById(Integer id) {
template.update("delete from account whew id = ?",id);
}
public void updateAcc(account account) {
template.update("update account set name =? ,money =? where id =? ",account.getName(),account.getMoney(),account.getId());
}
}
4.3config
public class AccountRowMapper implements RowMapper<account> {
public account mapRow(ResultSet resultSet, int i) throws SQLException {
account account = new account();
account.setId(resultSet.getInt("id"));
account.setName(resultSet.getString("name"));
account.setMoney(resultSet.getFloat("money"));
return account;
}
}
@Configuration
@PropertySource("classpath:jdbcConfig.properties")
public class jdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean(name="dataSource")
public DataSource createDataSource() throws PropertyVetoException {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUsername(username);
ds.setPassword(password);
ds.setDriverClassName(driver);
ds.setUrl(url);
return ds;
}
@Bean(name="template")//当使用注解时,如果有参数,spring会查找
public JdbcTemplate createQueryRunner(DataSource dataSource)
{
return new JdbcTemplate(dataSource);
}
}
@Configuration
@ComponentScan("lml")//用于指定spring在初始化容器时要扫描的包
@Import({jdbcConfig.class,TransactionConfig.class})
@EnableAspectJAutoProxy
@EnableTransactionManagement
public class SpringConfigu {
}
public class TransactionConfig {
@Bean(name = "transactionManager")
public PlatformTransactionManager createTransactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
4.4 jdbcConfig.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springOne?serverTimezone=UTC
jdbc.username=root
jdbc.password=admin
4.5 test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfigu.class)
public class one {
@Autowired
private IaccountService a;
@Test
public void one() throws SQLException {
a.transfer("aa","bb",100f);
}
}