Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 333|回复: 0

[默认分类] Hibernate | Spring JPA | MySQL 使用过程遇到的一些问题

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-4-23 14:35:22 | 显示全部楼层 |阅读模式

    1. 使用过程
    2. 背景
    3. 遇到问题
      
       3.1 不指定Hibernate数据库方言,默认SQL生成方式
       3.2 抛出异常Hibernate加入了@Transactional事务不会回滚
       3.3 Hibernate使用Spring Test测试加入了@Transactional事务无论如何数据库插入不成功
       3.4 Hibernate在使用MyISAM引擎也可以回滚?
       3.5 Hibernate在使用生成策略是IDENTITY不能回滚事务,AUTO可以
       3.6 使用MyISAM引擎下@Controller下使用事务回滚不成功,@Service下成功
       
    4. 总结

    1. 使用过程
      在项目中我使用Spring Boot 2.0.0.RELEASE开发并且集成了Spring JPA;我这里将Hibernate版本设置为5.1.2.Final,这里做修改主要是因为LocalDate跟数据库映射时有些问题才做更换,其他基本没什么大的问题;数据库使用了MySQL
      
    2. 背景
      使用MySQL,所以先对MySQL做一些了解,这里MySQL数据库中有四种存储引擎,主要介绍两种,分别为
    1. MyISAM
    复制代码
    1. InnoDB
    复制代码
    ,它们两个的区别如下:

      
       
       
       InnoDB
       MyISAM
       
      
      
       
       访问速度
       相对慢
       快
       
       
       事务
       支持
       不支持
       
       
       外键
       支持
       不支持
       
       
       应用场景
       需要事务提交、回滚功能应用
       以查询为主的应用
       
      

    3. 遇到问题
    3.1 不指定Hibernate数据库方言,默认SQL生成方式
    在不指定方言的情况下默认使用了
    1. MySQL5Dialect
    复制代码
    ,这样在打印
    1. create table
    复制代码
    命令时会在后面指定它的数据库引擎为
    1. MyISAM
    复制代码
    ,这样生成的数据库是不支持外键的,也是不支持事务性操作的。请注意是数据库。
    3.2 抛出异常Hibernate加入了
    1. @Transactional
    复制代码
    事务不会回滚

    现在这里有个实体类:

    1. [code]@Entity
    2. @Data
    3. public class Test{
    4.     @Id
    5.     @GeneratedValue(strategy = GenerationType.IDENTITY)
    6.     private Integer id;
    7.    
    8.     private String name;
    9.    
    10. }
    复制代码
    [/code]

    我们保存需要保存一个
    1. Test
    复制代码
    实例时发现抛出了一个异常数据库居然保存成功,代码如下:

    1. [code]Service:
    2.     @Resource
    3.     private TestDao testDao;
    4.     @Transactional
    5.     public void test(){
    6.         Test test = new Test();
    7.         test.setName("test");
    8.         testDao.save(test);
    9.         int a = 1 / 0;
    10.     }
    复制代码
    [/code]

    这里我们要看回去MySQL生成的方式,默认是使用了
    1. MyISAM
    复制代码
    这是不支持事务的,如果向数据库保存了数据,那么事务回滚也是不管用的,所以,现在我们需要指定配置数据库的方言,在Spring Boot中可在
    1. application.properties
    复制代码
    配置如下:
    1. [code]spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
    复制代码
    [/code]
    如果是xml配置的可以这么配置
    1. [code]<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
    复制代码
    [/code]
    这样我们重新运行生成的表可以有外键生成也可以支持数据库事务,当然数据就可以回滚了
    当然了,除了以上的解决方法之外,其实还有一个不怎么好的解决方法,那就是将
    1. Test
    复制代码
    中的
    1. id
    复制代码
    生成策略注解改为如下内容:

    1. [code]@Entity
    2. @Data
    3. public class Test{
    4.     @Id
    5.     @GeneratedValue(strategy = GenerationType.AUTO)
    6.     private Integer id;
    7.    
    8.     private String name;
    9.    
    10. }
    复制代码
    [/code]

    对于这个为什么可以,请接着往下面看
    3.3 Hibernate使用Spring Test测试加入了
    1. @Transactional
    复制代码
    事务无论如何数据库插入不成功

      这里使用上面修改成AUTO的实体类
      在测试类里面我们可以保存我们一个
    1. Test
    复制代码
    对象,测试代码如下:

    1. [code]junit.Test
    2.     @Test
    3.     @Transactional
    4.     public void test(){
    5.         Test test = new Test();
    6.         test.setName("test");
    7.         testDao.save(test);
    8.     }
    复制代码
    [/code]

    上面没有任何异常抛出,进度条也绿了,但是数据插入数据库不成功,这时,可以看下控制台打印输出的语句:

    1. [code]//....前面有很多,不写出来了
    2. transaction manager [org.springframework.orm.jpa.JpaTransactionManager@5e5ddfbc]; rollback [true]
    复制代码
    [/code]

    这里我大胆的猜测就是Spring Test自动帮我们把事务回滚了,我们如果要看到把数据插入数据库的话只是需要在test方法加入注解,如

    1. [code]    @Test
    2.     @Transactional
    3.     @Rollback(false) //设置事务不自动回滚
    4.     public void test(){
    5.         Test test = new Test();
    6.         test.setName("test");
    7.         testDao.save(test);
    8.     }
    复制代码
    [/code]

    3.4 Hibernate在使用MyISAM引擎也可以回滚?
      我在之前写的会员管理系统中是没有指定生成方言的,默认是使用了MyISAM,但是在Service中出现了异常还是可以回滚,怎么回事?
      这是因为我们在
    1. save
    复制代码
    之后Hibernate不会立马执行SQL的,除非是事务提交了,我在事务提交之前抛出了异常,所以在Hibernate的缓存中的SQL是不会执行成功的,因此就用假的回滚现象,这不是数据库提供的回滚功能。
      
    3.5 Hibernate在使用生成策略是IDENTITY不能回滚事务,AUTO可以
      
      这是因为如果使用了
    1. IDENTITY
    复制代码
    是数据库维护我们的主键,Hibernate为了获取id是需要向数据库插入数据才能获得id的值的,所以会执行SQL,在使用MyISAM引擎的情况下是不能回滚事务的
      如果用了AUTO那么不需要数据库维护,Hibernate自己维护是不需要向数据库要主键的,那么不会立马执行SQL就跟上一个问题一样的结果。所以这里的生成策略使用uuid也是可以的,只要不是数据库维护。
      
      
    3.6 使用MyISAM引擎下有缓存的情况
    1. @Controller
    复制代码
    下使用事务回滚不成功,
    1. @Service
    复制代码
    下成功

      在Controller层使用
    1. @Transactional
    复制代码
    事务是不会回滚的,但是Service层就可以,如果把
    1. @Controller
    复制代码
    替换成
    1. @Component
    复制代码
    也是成功的。
      我做了下调试,发现Controller调用方法如下图:
      
    Service调用事务方法如下图:
      
    也就是代理方式不同,一种是JDK代理一种是CGLib代理,这个导致了AOP实现的事务是调用不成功的,具体可以自行搜索AOP与动态代理相关的知识(原谅我知识局限)。
    4. 总结
       这里遇到大部分问题终其原因都是MySQL引擎使用或是没有指定方言的原因吧,所以,没有性能方面的要求或者是小白请使用
    1. InnoDB
    复制代码
    引擎。
       而对于我来说,这些异常手动catch算是学到了些东西,但是会遇到问题说明自己还是没有了解它,不说了,好好学习。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-17 07:12 , Processed in 0.380350 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表