maven依赖
org.springframework:spring-context:5.3.24
org.springframework:spring-core:5.3.24
org.springframework:spring-beans:5.3.24
org.springframework:spring-aop:5.3.24
org.springframework:spring-tx:5.3.24
org.springframework:spring-jdbc:5.3.24
commons-dbcp:commons-dbcp:1.4
org.aspectj:aspectjweaver:1.9.7
com.mysql:mysql-connector-j:8.0.31
业务代码
public class Foo {
private Integer id;
private String name;
private Double scores;
private Integer version;
private Byte isDeleted;
//getters and setters
}
/*接口*/
public interface FooService {
Foo getFoo(String fooName);
void updateFoo(Foo foo);
}
/*实现类FooServiceImpl*/
public class FooServiceImpl implements FooService{
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public Foo getFoo(String fooName) {
String sql = "SELECT * FROM foo_test where name=?;";
Foo foo = (Foo) jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Foo.class), fooName);
System.out.println(foo.getScores());
return foo;
}
@Override
public void updateFoo(Foo foo) {
String sql = "UPDATE foo_test SET version = version+1 WHERE name=?;";
jdbcTemplate.update(sql, foo.getName());
int i = 1/0;
}
}
/*实现类BarServiceImpl*/
public class BarServiceImpl implements BarService{
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public Bar getBar(String barName) {
String sql = "SELECT * FROM foo_test where name=?;";
Bar bar = (Bar) jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Bar.class), barName);
System.out.println(bar.getScores());
return bar;
}
@Override
public void updateBar(Bar bar) {
String sql = "UPDATE foo_test SET version = version+1 WHERE name=?;";
jdbcTemplate.update(sql, bar.getName());
int i = 1/0;
}
}
/*测试类*/
public class App
{
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
FooService fooService = ctx.getBean(FooService.class);
// 修改
Foo foo = new Foo();
foo.setName("onion");
fooService.updateFoo(foo);
// 修改2
BarService barService = ctx.getBean(BarService.class);
Bar bar = new Bar();
bar.setName("onion2");
barService.updateBar(bar);
}
}
spring.xml配置
tx:advice可选项:https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#transaction-declarative-txadvice-settings
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 遇到异常不回滚 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" no-rollback-for="Throwable"/>
</tx:attributes>
</tx:advice>
<!-- 遇到异常立即回滚 -->
<tx:advice id="anotherTxAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" rollback-for="Throwable"/>
</tx:attributes>
</tx:advice>
<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface -->
<aop:config>
<aop:pointcut id="fooServiceOperation" expression="execution(* org.transaction.declare.service.FooService.*(..))"/>
<aop:pointcut id="barServiceOperation" expression="execution(* org.transaction.declare.service.BarService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
<aop:advisor advice-ref="anotherTxAdvice" pointcut-ref="barServiceOperation"/>
</aop:config>
<!-- don't forget the DataSource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://"/>
<property name="username" value=""/>
<property name="password" value=""/>
</bean>
<!-- similarly, don't forget the TransactionManager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- other <bean/> definitions here -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="fooService" class="org.declaretransaction.service.FooServiceImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="barService" class="org.transaction.declare.service.BarServiceImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
</beans>