一、事务的相关概念概念
1、事务:事务指的是逻辑上的一组操作,这组操作要么全部成功,要么全部失败。这一组操作需要满足事务的四大特效(ACID)。
2、事务的传播行为:事务的传播行为是指在开始当前事务前,如果一个事务上下文已经存在,此时采取的事务执行行为。Spring 的 TransactionDefinition 接口中定义了如下的事务传播行为:
- PROPAGATION_REQUIRED(默认) :如果当前已存在事务,则加入该事务;如果当前不存在事务,则创建一个新的事务。
- PROPAGATION_REQUIRES_NEW :无论如何创建一个新的事务;如果当前存在事务,将当前事务挂起。
- PROPAGATION_SUPPORTS :如果当前已存在事务,则加入事务;如果当前不存在事务,则以非事务方式执行。
- PROPAGATION_NOT_SUPPORTED :以非事务方式执行;如果当前已存在事务,则将当前事务挂起。
- PROPAGATION_NEVER :以非事务方式执行;如果当前已存在事务,则抛出异常。
- PROPAGATION_MANDATORY :如果当前已存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
- PROPAGATION_NESTED:如果当前已存在事务,则创建一个事务作为当前事务的嵌套事务执行;如果当前不存在事务,则创建一个新的事务。
注:上述事务传播行为大同小异,一般记住默认的事务传播行为(PROPAGATION_REQUIRED)即可。值得注意的是,以 PROPAGATION_NESTED 启动的事务如果内嵌于外部事务中,此时内嵌事务并不是一个独立的事务。只有外部事务提交,内嵌事务才能提交,外部事务回滚也会导致内嵌事务回滚。内嵌事务依赖于外部事务而存在,内嵌事务相当于安全点的作用。
3、事务的超时:事务超时是指一个事务所允许执行的最长时间。如果超过该时间事务还没执行完毕,则自动回滚事务。
4、事务的只读属性:事务的只读属性是指对事务性资源(如数据库资源等)执行只读操作。比如事务只读属性设置为 true ,那么只能对数据库执行读操作(如 select ),不能执行写操作(如 insert、update 等)。当我们确定只对数据库进行只读操作时,开启该属性有利于提高事务处理的性能。
5、事务的回滚规则:事务的回滚规则是指在抛出某些异常时事务的处理方式。默认情况下,如果事务抛出未检查异常(也称运行时异常,指所有继承自 RuntimeException 的异常),则回滚事务;如果没有抛出异常或抛出已检查异常,则提交事务。在实际应用中,我们可以自定义回滚规则,比如在抛出某些未检查异常时提交事务,抛出某些已检查异常时回滚事务。
二、事务的四大特性(ACID)
1、原子性(Atomicity):一个事务中的SQL,要么全部执行,要么全部不执行;
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
2、一致性(Consistency):一个事务执行前后,数据库中的所有约束依然然满足;
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
3、持久性(Durability):一个事务执行完成后,事务对数据的修修改必须持久化到数据库中。
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。
4、隔离性(Isolation):一个事务执行过程中,数据不受另一个事务的影响;
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,在介绍数据库提供的各种隔离级别之前,我们先看看如果不考虑事务的隔离性,会发生的几种问题:
a、脏读:脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户A向用户B转账100元,对应SQL命令如下
update account set money=money+100 where name=’B’; (此时A通知B)
update account set money=money - 100 where name=’A’;
当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。
b、不可重复读:不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……
c、虚读(幻读)
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
三、MySQL数据库的四种隔离级别:
① Serializable (序列化):可避免脏读、不可重复读、幻读的发生;性能最低,事务只能一个个执行,解决所有问题。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生,可能出现幻读现象(MySQL默认);。
③ Read committed (读已提交):可避免脏读的发生(大多数数据库默认);。
④ Read uncommitted (读未提交):最低级别,性能最高;事务中三种问题都可能产生;
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。
在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。
在MySQL数据库中查看当前事务的隔离级别:
select @@tx_isolation;
在MySQL数据库中设置事务的隔离 级别:
set [glogal | session] transaction isolation level 隔离级别名称;
set tx_isolation=’隔离级别名称;’
或者:
注意:设置数据库的隔离级别一定要是在开启事务之前!
如果是使用JDBC对数据库的事务设置隔离级别的话,也应该是在调用Connection对象的setAutoCommit(false)方法之前。调用Connection对象的setTransactionIsolation(level)即可设置当前链接的隔离级别,至于参数level,可以使用Connection对象的字段:
在JDBC中设置隔离级别的部分代码:
补充:隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说,一个Connection对象相当于一个链接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他链接Connection对象无关。
Spring 的 TransactionDefinition 接口中定义了五个表示隔离级别的常量,分别是:
ISOLATION_DEFAULT(默认) :表示采用底层数据库的隔离级别,比如底层数据库采用的是 MySQL ,则采用的隔离级别就是 REPEATABLE_READ 。
ISOLATION_READ_UNCOMMITTED :对应隔离级别 READ_UNCOMMITTED 。
ISOLATION_READ_COMMITTED :对应隔离级别 READ_COMMITTED 。
ISOLATION_REPEATABLE_READ :对应隔离级别 REPEATABLE_READ 。
ISOLATION_SERIALIZABLE :对应隔离级别 SERIALIZABLE 。
四、Spring提供了的两种事务管理方式:
1、编程式事务管理
PlatformTransactionManager实现编程式事务管理
步骤1、配置Spring事务管理器
springConfig.xml:
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!-- 配置Spring自动扫描的目录 -->
<context:component-scan base-package="com.prosay.transaction"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/java?useSSL=true"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置Spring事务管理器(无论哪种方式都要这个事务管理器) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
步骤2、获取PlatformTransactionManager实例
步骤3、获取TransactionStatus对象,打开事务
步骤4、提交事务/回滚事务
@Component("orderService4Platform")
public class OrderService4Platform implements IOrderService {
@Autowired
private IOrderDao orderDao;
@Autowired
@Qualifier("productDaoImpl4Platform")
private IProductDao productDao;
@Autowired
private PlatformTransactionManager transaction;
public void createOrder(){
//打开默认事务
TransactionStatus status = transaction.getTransaction(new DefaultTransactionDefinition());
try {
Order order = new Order();
order.setOrder_id(104);
order.setProduct_id(1004);
order.setCustomer("Kevin");
order.setNumber(100);
int row = orderDao.insertOrder(order);
System.out.println("添加订单影响行数:"+row);
if(row>0){
//下单成功,修改库存
boolean falg = productDao.updateProduct(order);
if(falg){
System.out.println("库存修改成功。");
}else{
System.out.println("库存修改失败。");
}
}
//通过事务管理器提交当前事务
transaction.commit(status);
} catch (Exception e) {
//通过事务管理器回滚当前事务
transaction.rollback(status);
e.printStackTrace();
}
}
}
@Component("productDaoImpl4Platform")
public class ProductDaoImpl4Platform implements IProductDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public boolean updateProduct(Order order) {
String sql = "update t_product set count = count-? where product_id=?";
int row = jdbcTemplate.update(sql, order.getNumber(), order.getProduct_id());
// MessageUtil.sendMessage();
if(row>0){
return true;
}
return false;
}
}
@Component
public class OrderDaoImpl implements IOrderDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int insertOrder(Order order) {
String sql = "insert into t_order(order_id, product_id, customer, number) values(?,?,?,?)";
int row = jdbcTemplate.update(sql, order.getOrder_id(), order.getProduct_id(), order.getCustomer(), order.getNumber());
System.out.println("execute row:"+row);
return row;
}
}
public class Client {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
IOrderService orderService = (IOrderService) context.getBean("orderService4Platform");
orderService.createOrder();
}
}
TransactionTemplate实现编程式事务管理
步骤1、配置Spring事务管理器
springConfig.xml
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!-- 配置Spring自动扫描的目录 -->
<context:component-scan base-package="com.prosay.transaction"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/java?useSSL=true"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置Spring事务管理器(无论哪种方式都要这个事务管理器) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置TransactionTemplate -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
<!-- 定义事务隔离级别 -->
<property name="isolationLevelName" value="ISOLATION_DEFAULT"></property>
<!-- 定义事务传播属性 -->
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"></property>
</bean>
</beans>
步骤2、获取TransactionTemplate实例
步骤3、通过TransactionTemplate.execute(),打开事务环境
public class Client {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
IOrderService orderService = (IOrderService) context.getBean("orderService4Template");
orderService.createOrder();
}
}
@Component("orderService4Template")
public class OrderService4Template implements IOrderService {
@Autowired
private IOrderDao orderDao;
@Autowired
@Qualifier("productDaoImpl4Template")
private IProductDao productDao;
@Autowired
private TransactionTemplate transactionTemplate;
public void createOrder(){
Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() {
public Integer doInTransaction(TransactionStatus status) {
Order order = new Order();
order.setOrder_id(104);
order.setProduct_id(1004);
order.setCustomer("Kevin");
order.setNumber(100);
int row = orderDao.insertOrder(order);
System.out.println("添加订单影响行数:"+row);
if(row>0){
//下单成功,修改库存
boolean falg = productDao.updateProduct(order);
if(falg){
System.out.println("库存修改成功。");
}else{
System.out.println("库存修改失败。");
}
}
return row;
}
});
}
}
@Component("productDaoImpl4Template")
public class ProductDaoImpl4Template implements IProductDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public boolean updateProduct(Order order) {
String sql = "update t_product set count = count-? where product_id=?";
int row = jdbcTemplate.update(sql, 100, 1004);
// MessageUtil.sendMessage();
if(row>0){
return true;
}
return false;
}
}
2、声明式事务管理
注解实现声明式事务管理
步骤1、开启注解式事务管理
springConfig.xml
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!-- 配置Spring自动扫描的目录 -->
<context:component-scan base-package="com.prosay.transaction"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/java?useSSL=true"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置Spring事务管理器(无论哪种方式都要这个事务管理器) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置启动注解方式使用事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
步骤2、使用@Transactional注解使用事务
public class Client {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
IOrderService orderService = (IOrderService) context.getBean("orderService4Annotation");
orderService.createOrder();
}
}
@Component("orderService4Annotation")
public class OrderService4Annotation implements IOrderService {
@Autowired
private IOrderDao orderDao;
@Autowired
@Qualifier("productDaoImpl4Annotation")
private IProductDao productDao;
@Transactional(propagation=Propagation.REQUIRED)
public void createOrder(){
Order order = new Order();
order.setOrder_id(104);
order.setProduct_id(1004);
order.setCustomer("Kevin");
order.setNumber(100);
int row = orderDao.insertOrder(order);
System.out.println("添加订单影响行数:"+row);
if(row>0){
try {
//下单成功,修改库存
boolean falg = productDao.updateProduct(order);
if(falg){
System.out.println("库存修改成功。");
}else{
System.out.println("库存修改失败。");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@Component("productDaoImpl4Annotation")
public class ProductDaoImpl4Annotation implements IProductDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public boolean updateProduct(Order order) {
String sql = "update t_product set count = count-? where product_id=?";
int row = jdbcTemplate.update(sql, 100, 1004);
// MessageUtil.sendMessage();
if(row>0){
return true;
}
return false;
}
}
补充:
在上例上OrderService4Annotation添加事务@Transactional(propagation=Propagation.REQUIRED)
和ProductDaoImpl4Annotation添加的事务@Transactional(propagation=Propagation.REQUIRES_NEW)
注解参数是事务的传播属性,上文已经提到REQUIRES_NEW表示当当前有事务时,挂起当前事务,新建事务,这就把这里的下单和修改库存变成两个事务了,由事务的隔离性,当修改库存时出现异常时,库存修改不会成功,事务会回滚;在createOrder方法中处理了修改库存的异常,所以createOrder不会抛出异常,下单的事务没有问题,事务不会回滚。这就会有下单成功,但是库存不会修改的情况。
TransactionTemplate实现编程式事务管理
步骤1、配置事务属性
步骤2、配置事务切点
springConfig.xml
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!-- 配置Spring自动扫描的目录 -->
<context:component-scan base-package="com.prosay.transaction"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/java?useSSL=true"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置Spring事务管理器(无论哪种方式都要这个事务管理器) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- AOP配置声明式事务管理 -->
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 方法名可以直接指定也可以用正则表达式去匹配,propagation是隔离级别属性,还可以加入其它属性 -->
<tx:method name="createOrder" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(** com.prosay.transaction.service.*.*(..))" id="pointCut"/>
<aop:advisor advice-ref="advice" pointcut-ref="pointCut"/>
</aop:config>
</beans>
public class Client {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
IOrderService orderService = (IOrderService) context.getBean("orderService4Advice");
orderService.createOrder();
}
}
@Component("orderService4Advice")
public class OrderService4Advice implements IOrderService {
@Autowired
private IOrderDao orderDao;
@Autowired
@Qualifier("productDaoImpl4Advice")
private IProductDao productDao;
public void createOrder(){
Order order = new Order();
order.setOrder_id(104);
order.setProduct_id(1004);
order.setCustomer("Kevin");
order.setNumber(100);
int row = orderDao.insertOrder(order);
System.out.println("添加订单影响行数:"+row);
if(row>0){
//下单成功,修改库存
boolean falg = productDao.updateProduct(order);
if(falg){
System.out.println("库存修改成功。");
}else{
System.out.println("库存修改失败。");
}
}
}
}
@Component("productDaoImpl4Advice")
public class ProductDaoImpl4Advice implements IProductDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public boolean updateProduct(Order order) {
String sql = "update t_product set count = count-? where product_id=?";
int row = jdbcTemplate.update(sql, 100, 1004);
// MessageUtil.sendMessage();
if(row>0){
return true;
}
return false;
}
}