写在前面:本次讲解均在MAC OS环境下进行;因为对于数据库,我们在增删改的过程中可能会发生错误,导致存储数据不一致,而事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。
目录
-
Innodb与Myisam引擎的区别于应用场景
-
实例操作
一、Innodb与Myisam引擎的区别于应用场景
Innodb和Myisam是mysql的两种引擎,我在初次尝试事务管理时,遇到了引擎这个问题,当时我的mysql默认是用了Myisam,结果没有达到我想要的效果,下面就说说这两种引擎有什么不同。参考博文fengna
1、Innodb
- 事物安全型引擎,支持事务处理等高级处理。
- 行级锁(可以参考这篇锁机制)
- 对于INSERT和UPDATE操作有很好的适应性,面对大量的这两类操作,Innodb更好的选择。
- 查询方式:因为其不保存表的具体行数,所以在执行select count(*) from table时,要扫描一边整个表来计算有少行。
- 支持外键
- 在做select操作时,维护的东西相对Myisam要多:要缓存数据库、寻址要映射到块再到行、维护MVCC一致(即使你的场景没有,它也要去维护)
总结:适合(1)做可靠性要求比较高,或者进行事物处理;(2)对表更新和插入相当频繁,并且行锁定的机会比较大的情况
2、Myisam
- 非事物安全型
- 表锁级(可以参考这篇锁机制)
- 对于大量的select,它支持的比较好
- Myisam保存行数,所以对于select count(*) from table操作,它只需简单读出保存好的行数。
- 不支持外键
- 查询速度快:只需缓存索引块、寻址直接记录文件的offset、不需要维护MVCC一致
总结:适合(1)做很多count计算(2)插入不频繁,但查询非常频繁(3)没有事物处理
此外提醒一点在进行select count(*) from table操作时,如果count(*)语句包含 where条件时,两种引擎的操作是一样的。
在了解以上区别后,对于我们现在要进行的事务管理,我们应该选择Innodb引擎,但我开头说了,我建的表默认是Myisam,所以下面讲解下如何更改引擎。
3、更改mysql引擎
我是直接用代码来修改的,因为我表的数据很少,所以可以直接这样,但如果数据量多请参考这篇文章。
我用的是sequel pro管理数据库,所以就直接在里面改了,下面是截图
在query窗口输入:ALTER TABLE girl ENGINE=InnoDb ,其中girl是表名,然后点击Run Current按钮运行即可。
二、实例操作
实例描述:给girl表同时插入两条女生记录,测试时特地使其中一个女生的记录有错无法插入,观察另一条女生记录是否被存储(期望是要么都被成功存入,要么都不被存入)
1、在spring boot里新建事物类
package com.imooc.girl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
@Service
public class GirlService {
@Autowired
private GirlRepository girlRepository;
@Transactional
public void insertTwo(){
Girl girlA = new Girl();
girlA.setCupSize("A");
girlA.setAge(18);
girlRepository.save(girlA);
Girl girlB = new Girl();
girlB.setCupSize("B");
girlB.setAge(19);
girlRepository.save(girlB);
}
}
截图:
2、在GirlController类里添加插入方法
package com.imooc.girl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
public class GirlController {
@Autowired
private GirlService girlService;
/**
* 事物处理测试
*/
@PostMapping(value = "/girls/two")
public void girlTwo(){
girlService.insertTwo();
}
}
测试是否都能成功添加:
没问题,接下来开始进入场景:将cupSize的值在数据库中限制长度为1,然后在插第二条记录时故意将cupSize赋值长度超过1,看能否达到期望。
修改属性:
重新赋值:
清空数据库,重新测试:
如上图所示,成功报错,接下来看下数据库情况:
很好,没有存储任何一条记录!
我们回到刚才建立的事务类(见下面代码),其中起关键作用的是@Transactional这个注解,这个注解就是在spring里用于事物管理功能的(你可以试着将此注解删除,看还能不能进行事物管理,这里就不演示了)
package com.imooc.girl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
@Service
public class GirlService {
@Autowired
private GirlRepository girlRepository;
@Transactional
public void insertTwo(){
Girl girlA = new Girl();
girlA.setCupSize("A");
girlA.setAge(18);
girlRepository.save(girlA);
Girl girlB = new Girl();
girlB.setCupSize("B");
girlB.setAge(19);
girlRepository.save(girlB);
}
}