1. 事务控制
1.1 原子性
关于原子性说明: 一个方法该方法中的业务要么同时成功/要么同时失败. 才能满足原子性的要求.
1.2 Spring中事务控制-@Transactional
1.2.1 注解说明
Spring针对于数据库中的事务控制,开发了一套注解**@Transactional**.其注解的核心用法采用AOP中的Around通知,实现了对事务的控制.
1.2.2 注解用法
1.Spring默认的事务策略:
1.如果控制的方法出现了运行时异常则事务自动的回滚.
2.如果控制的方法 检查异常(编译异常), 事务不会自动回滚,Spring任务程序既然已经提示需要异常的处理.则默认由程序员自己控制.Spring不负责管理.
2.注解属性
rollbackFor: 遇到什么类型, 异常回滚事务,
noRollbackFor: 遇到什么类型的异常 事务不回滚.
关于属性说明: 一般工作中都采用默认策略,特殊条件下才使用该配置.
1.2.2 关于AOP回顾
AOP: 在不影响源码的条件下,对方法进行扩展.
AOP通知类型: 1.Before 2.AfterReturning 3.AfterThrowing 4.After 5.Around
2. 全局异常处理机制
2.1 业务说明
一般在业务操作时,无法保证所有的操作都能正常运行.所以为了完全性,需要添加大量的try-catch代码. 效果如图:
需求: 如果将大量的try-catch代码直接写到业务中,导致业务代码混乱,所以需要将异常信息进行抽取.所有提供了全局异常处理机制. Spring4开始的.
2.2 全局异常处理实现
//全局异常处理,内部依然采用环绕通知的方式
//异常处理之后返回的JSON串.
//该全局异常处理机制,捕获Controller层的异常(其它层向上抛出异常)
@RestControllerAdvice
public class MyException {
/**
* 业务: 如果后端报错,应该及时提示前端用户,返回统一的对象
* SysResult对象. status=201/msg="xxx失败"
* 注解说明:
* @ExceptionHandler(RuntimeException.class)
* 当遇到某种异常时,全局异常处理机制有效!!
*/
@ExceptionHandler(RuntimeException.class)
public Object exception(Exception e){
//1.应该打印异常信息.
e.printStackTrace();
//2.返回特定的响应数据.
return SysResult.fail();
}
}
3 商品分类业务实现
3.1 实现页面跳转
需求: 当用户访问/itemCat路径时,应该跳转到ItemCat.vue页面中. 编辑路由文件.
页面效果展现
3.2 商品分类表结构分析
3.2.1 表数据结构
3.2.2 商品分类表数据结构
Sql代码演示:
/*查询一级商品分类信息*/
SELECT * FROM item_cat WHERE parent_id = 0
/*查询二级商品分类信息 parent_id = 1级的id*/
SELECT * FROM item_cat WHERE parent_id = 558
/*查询三级商品分类信息*/
SELECT * FROM item_cat WHERE parent_id = 559
3.2.3 ItemCat POJO属性
3.2.4 构建商品分类层级代码
3.3 商品分类查询实现
3.3.1 页面URL分析
3.3.2 业务接口文档
3.3.3 编辑ItemCatController
@RestController
@CrossOrigin
@RequestMapping("/itemCat")
public class ItemCatController {
@Autowired
private ItemCatService itemCatService;
/**
* URL: /itemCat/findItemCatList/{level}
* 参数: level 1/2/3
* 返回值: SysResult对象(List<ItemCat>)
*/
@GetMapping("/findItemCatList/{level}")
public SysResult findItemCatList(@PathVariable Integer level){
List<ItemCat> itemCatList = itemCatService.findItemCatList(level);
return SysResult.success(itemCatList);
}
}
3.3.4 编辑ItemCatService
@Service
public class ItemCatServiceImpl implements ItemCatService{
@Autowired
private ItemCatMapper itemCatMapper;
/**
* 3层商品分类嵌套 1一级分类(children(2级商品分类))
* 2一级分类(children(3级商品分类))
* 一级查询条件 parent_id=0
* 二级查询条件 parent_id=一级的ID
* 三级查询条件 parent_id=二级的ID
* @param level
* @return
*/
@Override
public List<ItemCat> findItemCatList(Integer level) {
long startTime = System.currentTimeMillis();
//1.查询一级商品分类信息
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("parent_id",0 );
List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);
//2.查询二级商品分类信息
for (ItemCat oneItemCat : oneList){
queryWrapper.clear();
queryWrapper.eq("parent_id",oneItemCat.getId());
List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);
//3.查询三级商品分类信息
for (ItemCat twoItemCat : twoList){
queryWrapper.clear();
queryWrapper.eq("parent_id",twoItemCat.getId());
List<ItemCat> threeList = itemCatMapper.selectList(queryWrapper);
twoItemCat.setChildren(threeList);
}
oneItemCat.setChildren(twoList);
}
long endTime = System.currentTimeMillis();
System.out.println("业务的执行时间为:"+(endTime-startTime)+"毫秒");
return oneList;
}
}
3.4 商品分类代码优化
3.4.1 代码中存在的问题
问题: 最大的问题在于for循环的嵌套. 嵌套太多层导致程序运行速度慢,占用内存高.
优化: 要求查询速度要快!!!
思路: 与数据库交互的频次太多了,导致性能出现问题. 优化设计
要求: 只查询一次数据库 即可以获取3级商品分类信息
3.4.2 商品分类查询优化设计
问题: 与数据库交互次数太多, 要求:只查询一次数据库 实现列表展现
设计:
1. 查询数据库中的所有的数据信息.
2. key: parentId value: 当前parentId下的所有的子级Map集合
3. 将查询的结果封装到Map集合中.
4. 如需获取子级数据信息,通过getKey 即可获取数据.
3.4.3 关于List集合引用对象的说明
说明:list集合定义之后,Map中获取的是引用地址,所以可以直接对 对象进行操作.
3.4.3 重构ItemCatService
@Service
public class ItemCatServiceImpl implements ItemCatService{
@Autowired
private ItemCatMapper itemCatMapper;
/**
* 1.准备Map集合,实现数据封装
* Map<key,value> = Map<parentId,List<ItemCat>>
* 2.封装业务说明
* map中key~~parentId
* 不存在:可以存储该key
* 同时封装一个List集合,将自己作为第一个元素封装到其中.
* 存在: 根据key获取所有子级集合,将自己追加进去 形成第二个元素.
*/
public Map<Integer,List<ItemCat>> itemCatMap(){
//1.定义Map集合
Map<Integer,List<ItemCat>> map = new HashMap<>();
//2.查询所有的数据库信息 1-2-3
List<ItemCat> list = itemCatMapper.selectList(null);
for(ItemCat itemCat :list){
int parentId = itemCat.getParentId();//获取父级ID
if(map.containsKey(parentId)){ //判断集合中是否已经有parentId
//有key 获取list集合 将自己追加到集合中
List<ItemCat> exeList = map.get(parentId);//引用对象
exeList.add(itemCat);
}else{
//没有key,将自己封装为第一个list元素
List<ItemCat> firstList = new ArrayList<>();
firstList.add(itemCat);
map.put(parentId,firstList);
}
}
return map;
}
@Override
public List<ItemCat> findItemCatList(Integer level) {
long startTime = System.currentTimeMillis();
Map<Integer,List<ItemCat>> map = itemCatMap();
//1.如果level=1 说明获取一级商品分类信息 parent_id=0
if(level == 1){
return map.get(0);
}
if(level == 2){ //获取一级和二级菜单信息
return getTwoList(map);
}
//3.获取三级菜单信息
//3.1获取二级商品分类信息 BUG:有的数据可能没有子级 如何处理
List<ItemCat> oneList = getTwoList(map);
for (ItemCat oneItemCat : oneList){
//从一级集合中,获取二级菜单列表
List<ItemCat> twoList = oneItemCat.getChildren();
for(ItemCat twoItemCat : twoList){
//查询三级商品分类 条件:parentId=2级ID
List<ItemCat> threeList = map.get(twoItemCat.getId());
twoItemCat.setChildren(threeList);
}
}
long endTime = System.currentTimeMillis();
System.out.println("耗时:"+(endTime - startTime)+"毫秒");
return oneList;
}
public List<ItemCat> getTwoList(Map<Integer,List<ItemCat>> map){
List<ItemCat> oneList = map.get(0);
for (ItemCat oneItemCat : oneList){//查询二级 parentId=1级Id
List<ItemCat> twoList = map.get(oneItemCat.getId());
oneItemCat.setChildren(twoList);
}
//二级嵌套在一级集合中,所有永远返回的都是1级.
return oneList;
}
/**
* 3层商品分类嵌套 1一级分类(children(2级商品分类))
* 2一级分类(children(3级商品分类))
* 一级查询条件 parent_id=0
* 二级查询条件 parent_id=一级的ID
* 三级查询条件 parent_id=二级的ID
* @param level
* @return
*/
/* @Override
public List<ItemCat> findItemCatList(Integer level) {
long startTime = System.currentTimeMillis();
//1.查询一级商品分类信息
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("parent_id",0 );
List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);
//2.查询二级商品分类信息
for (ItemCat oneItemCat : oneList){
queryWrapper.clear();
queryWrapper.eq("parent_id",oneItemCat.getId());
List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);
//3.查询三级商品分类信息
for (ItemCat twoItemCat : twoList){
queryWrapper.clear();
queryWrapper.eq("parent_id",twoItemCat.getId());
List<ItemCat> threeList = itemCatMapper.selectList(queryWrapper);
twoItemCat.setChildren(threeList);
}
oneItemCat.setChildren(twoList);
}
long endTime = System.currentTimeMillis();
System.out.println("业务的执行时间为:"+(endTime-startTime)+"毫秒");
return oneList;
}*/
}
1. 事务控制
1.1 原子性
关于原子性说明: 一个方法该方法中的业务要么同时成功/要么同时失败. 才能满足原子性的要求.
1.2 Spring中事务控制-@Transactional
1.2.1 注解说明
Spring针对于数据库中的事务控制,开发了一套注解**@Transactional**.其注解的核心用法采用AOP中的Around通知,实现了对事务的控制.
1.2.2 注解用法
1.Spring默认的事务策略:
1.如果控制的方法出现了运行时异常则事务自动的回滚.
2.如果控制的方法 检查异常(编译异常), 事务不会自动回滚,Spring任务程序既然已经提示需要异常的处理.则默认由程序员自己控制.Spring不负责管理.
2.注解属性
rollbackFor: 遇到什么类型, 异常回滚事务,
noRollbackFor: 遇到什么类型的异常 事务不回滚.
关于属性说明: 一般工作中都采用默认策略,特殊条件下才使用该配置.
1.2.2 关于AOP回顾
AOP: 在不影响源码的条件下,对方法进行扩展.
AOP通知类型: 1.Before 2.AfterReturning 3.AfterThrowing 4.After 5.Around
2. 全局异常处理机制
2.1 业务说明
一般在业务操作时,无法保证所有的操作都能正常运行.所以为了完全性,需要添加大量的try-catch代码. 效果如图:
需求: 如果将大量的try-catch代码直接写到业务中,导致业务代码混乱,所以需要将异常信息进行抽取.所有提供了全局异常处理机制. Spring4开始的.
2.2 全局异常处理实现
//全局异常处理,内部依然采用环绕通知的方式
//异常处理之后返回的JSON串.
//该全局异常处理机制,捕获Controller层的异常(其它层向上抛出异常)
@RestControllerAdvice
public class MyException {
/**
* 业务: 如果后端报错,应该及时提示前端用户,返回统一的对象
* SysResult对象. status=201/msg="xxx失败"
* 注解说明:
* @ExceptionHandler(RuntimeException.class)
* 当遇到某种异常时,全局异常处理机制有效!!
*/
@ExceptionHandler(RuntimeException.class)
public Object exception(Exception e){
//1.应该打印异常信息.
e.printStackTrace();
//2.返回特定的响应数据.
return SysResult.fail();
}
}
3 商品分类业务实现
3.1 实现页面跳转
需求: 当用户访问/itemCat路径时,应该跳转到ItemCat.vue页面中. 编辑路由文件.
页面效果展现
3.2 商品分类表结构分析
3.2.1 表数据结构
3.2.2 商品分类表数据结构
Sql代码演示:
/*查询一级商品分类信息*/
SELECT * FROM item_cat WHERE parent_id = 0
/*查询二级商品分类信息 parent_id = 1级的id*/
SELECT * FROM item_cat WHERE parent_id = 558
/*查询三级商品分类信息*/
SELECT * FROM item_cat WHERE parent_id = 559
3.2.3 ItemCat POJO属性
3.2.4 构建商品分类层级代码
3.3 商品分类查询实现
3.3.1 页面URL分析
3.3.2 业务接口文档
3.3.3 编辑ItemCatController
@RestController
@CrossOrigin
@RequestMapping("/itemCat")
public class ItemCatController {
@Autowired
private ItemCatService itemCatService;
/**
* URL: /itemCat/findItemCatList/{level}
* 参数: level 1/2/3
* 返回值: SysResult对象(List<ItemCat>)
*/
@GetMapping("/findItemCatList/{level}")
public SysResult findItemCatList(@PathVariable Integer level){
List<ItemCat> itemCatList = itemCatService.findItemCatList(level);
return SysResult.success(itemCatList);
}
}
3.3.4 编辑ItemCatService
@Service
public class ItemCatServiceImpl implements ItemCatService{
@Autowired
private ItemCatMapper itemCatMapper;
/**
* 3层商品分类嵌套 1一级分类(children(2级商品分类))
* 2一级分类(children(3级商品分类))
* 一级查询条件 parent_id=0
* 二级查询条件 parent_id=一级的ID
* 三级查询条件 parent_id=二级的ID
* @param level
* @return
*/
@Override
public List<ItemCat> findItemCatList(Integer level) {
long startTime = System.currentTimeMillis();
//1.查询一级商品分类信息
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("parent_id",0 );
List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);
//2.查询二级商品分类信息
for (ItemCat oneItemCat : oneList){
queryWrapper.clear();
queryWrapper.eq("parent_id",oneItemCat.getId());
List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);
//3.查询三级商品分类信息
for (ItemCat twoItemCat : twoList){
queryWrapper.clear();
queryWrapper.eq("parent_id",twoItemCat.getId());
List<ItemCat> threeList = itemCatMapper.selectList(queryWrapper);
twoItemCat.setChildren(threeList);
}
oneItemCat.setChildren(twoList);
}
long endTime = System.currentTimeMillis();
System.out.println("业务的执行时间为:"+(endTime-startTime)+"毫秒");
return oneList;
}
}
3.4 商品分类代码优化
3.4.1 代码中存在的问题
问题: 最大的问题在于for循环的嵌套. 嵌套太多层导致程序运行速度慢,占用内存高.
优化: 要求查询速度要快!!!
思路: 与数据库交互的频次太多了,导致性能出现问题. 优化设计
要求: 只查询一次数据库 即可以获取3级商品分类信息
3.4.2 商品分类查询优化设计
问题: 与数据库交互次数太多, 要求:只查询一次数据库 实现列表展现
设计:
1. 查询数据库中的所有的数据信息.
2. key: parentId value: 当前parentId下的所有的子级Map集合
3. 将查询的结果封装到Map集合中.
4. 如需获取子级数据信息,通过getKey 即可获取数据.
3.4.3 关于List集合引用对象的说明
说明:list集合定义之后,Map中获取的是引用地址,所以可以直接对 对象进行操作.
3.4.3 重构ItemCatService
@Service
public class ItemCatServiceImpl implements ItemCatService{
@Autowired
private ItemCatMapper itemCatMapper;
/**
* 1.准备Map集合,实现数据封装
* Map<key,value> = Map<parentId,List<ItemCat>>
* 2.封装业务说明
* map中key~~parentId
* 不存在:可以存储该key
* 同时封装一个List集合,将自己作为第一个元素封装到其中.
* 存在: 根据key获取所有子级集合,将自己追加进去 形成第二个元素.
*/
public Map<Integer,List<ItemCat>> itemCatMap(){
//1.定义Map集合
Map<Integer,List<ItemCat>> map = new HashMap<>();
//2.查询所有的数据库信息 1-2-3
List<ItemCat> list = itemCatMapper.selectList(null);
for(ItemCat itemCat :list){
int parentId = itemCat.getParentId();//获取父级ID
if(map.containsKey(parentId)){ //判断集合中是否已经有parentId
//有key 获取list集合 将自己追加到集合中
List<ItemCat> exeList = map.get(parentId);//引用对象
exeList.add(itemCat);
}else{
//没有key,将自己封装为第一个list元素
List<ItemCat> firstList = new ArrayList<>();
firstList.add(itemCat);
map.put(parentId,firstList);
}
}
return map;
}
@Override
public List<ItemCat> findItemCatList(Integer level) {
long startTime = System.currentTimeMillis();
Map<Integer,List<ItemCat>> map = itemCatMap();
//1.如果level=1 说明获取一级商品分类信息 parent_id=0
if(level == 1){
return map.get(0);
}
if(level == 2){ //获取一级和二级菜单信息
return getTwoList(map);
}
//3.获取三级菜单信息
//3.1获取二级商品分类信息 BUG:有的数据可能没有子级 如何处理
List<ItemCat> oneList = getTwoList(map);
for (ItemCat oneItemCat : oneList){
//从一级集合中,获取二级菜单列表
List<ItemCat> twoList = oneItemCat.getChildren();
for(ItemCat twoItemCat : twoList){
//查询三级商品分类 条件:parentId=2级ID
List<ItemCat> threeList = map.get(twoItemCat.getId());
twoItemCat.setChildren(threeList);
}
}
long endTime = System.currentTimeMillis();
System.out.println("耗时:"+(endTime - startTime)+"毫秒");
return oneList;
}
public List<ItemCat> getTwoList(Map<Integer,List<ItemCat>> map){
List<ItemCat> oneList = map.get(0);
for (ItemCat oneItemCat : oneList){//查询二级 parentId=1级Id
List<ItemCat> twoList = map.get(oneItemCat.getId());
oneItemCat.setChildren(twoList);
}
//二级嵌套在一级集合中,所有永远返回的都是1级.
return oneList;
}
/**
* 3层商品分类嵌套 1一级分类(children(2级商品分类))
* 2一级分类(children(3级商品分类))
* 一级查询条件 parent_id=0
* 二级查询条件 parent_id=一级的ID
* 三级查询条件 parent_id=二级的ID
* @param level
* @return
*/
/* @Override
public List<ItemCat> findItemCatList(Integer level) {
long startTime = System.currentTimeMillis();
//1.查询一级商品分类信息
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("parent_id",0 );
List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);
//2.查询二级商品分类信息
for (ItemCat oneItemCat : oneList){
queryWrapper.clear();
queryWrapper.eq("parent_id",oneItemCat.getId());
List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);
//3.查询三级商品分类信息
for (ItemCat twoItemCat : twoList){
queryWrapper.clear();
queryWrapper.eq("parent_id",twoItemCat.getId());
List<ItemCat> threeList = itemCatMapper.selectList(queryWrapper);
twoItemCat.setChildren(threeList);
}
oneItemCat.setChildren(twoList);
}
long endTime = System.currentTimeMillis();
System.out.println("业务的执行时间为:"+(endTime-startTime)+"毫秒");
return oneList;
}*/
}