记遇到的问题

  • 1. 问题: SQL中数值类型数据和字符串比较,会优先取字符串中包含的数值,如果不包含数值则默认为0

  • 2. 问题:重复Bean注入org.springframework.beans.factory.NoUniqueBeanDefinitionException
    解决方法:

1. @Qualifier("beanName")
在引用注入时,使用@Qualifier注解来指定注入

2. @Primary
在定义新的Bean时,用于声明优先注入
  • 3. 问题: SQL中有having函数作为查询条件,使用PageHelper插件报错Unknown column '' in 'having clause'
    原因:因为PageHelper插件会默认执行一条count(0)统计语句,此时会把原分页查询SQL中的查询结果字段替换为count(0)函数,此时having函数用到的字段边会不存在导致SQL执行报错
    解决方法:
1. SQL语句中加一个DISTINT函数,这样PageHelper插件执行统计函数时便不会替换查询字段,而把之前的查询语句当作一个子表去重新包裹指定统计函数

2. 手动修改原SQL语句为嵌套的子表查询
  • 4. 问题: 在数据库中执行SELECT * FROM information_schema.innodb_trx;语句查询在执行中的事务时,出现LOCK WAIT(mysql死锁)
    注: 超过数据库配置的锁等待时间:innodb_lock_wait_timeout则会抛出异常LOCK_WAIT_TIMEOUT
    原因一: 高并发的情况下,Spring事务造成数据库死锁,后续操作超时抛出异常LOCK_WAIT_TIMEOUT
    原因二: MySQL数据库隔离级别为可重复读(REPEATABLE READ)时,Spring的声明式事务@Transactional的事务传播中存在嵌套事务(传播行为如:PROPAGATION_REQUIRES_NEW/PROPAGATION_NESTED),主事务对A表产生了间隙锁(Gap Lock),嵌套事务又对此表进行了更新操作(如:insert/update/delete)正好在在间隙锁加锁范围内,则会进入锁等待LOCK WAIT(mysql死锁),超过数据库配置的锁等待时间:innodb_lock_wait_timeout则会抛出异常LOCK_WAIT_TIMEOUT
    注:间隙锁(Gap Lock)Innodb可重复读(REPEATABLE READ)提交下为了解决幻读问题时引入的锁机制。

解决方法:

# 应急方法:
1. show full processlist; 找出出现问题的进程;
2. kill掉出现问题的进程。

# 根本解决办法:
1. select * from information_schema.innodb_trx;  查看有是哪些事务占据了表资源
2. 找到对应的程序代码,如原因二是嵌套事务导致,可以把主事务中因为未命中索引导致的锁表操作进行修改,避免锁表

# 其他办法:
增加锁等待时间,即增大下面配置项参数值,单位为秒(s) innodb_lock_wait_timeout=500
优化存储过程,事务避免过长时间的等待

间隙锁相关可参考以下两篇文章:
间隙锁详解
MySQL的锁机制 - 记录锁、间隙锁、临键锁

  • 5. 问题: 处理第三方回调时,需要加锁(如:分布式锁redisson)来保证只处理一次回调请求(如:易宝支付回调会反复发送回调确认),如果加锁和释放锁的操作是在事务内部,高并发情况下会因为锁释放了但是事务没提交导致重复执行锁内的代码片段进而影响到数据的准确性
    解决方法:
# 方法一:
在加锁执行的代码中,新增个处理标记,声明此段代码已被处理过,无需重复处理
如:在redis中设置个有期限的唯一标识(有效期根据实际运行场景规定)

# 方法二:
可以在存信息的数据库表中新增唯一索引来确保数据的唯一性

推荐两种方法一,方法二结合使用

# 方法三:
把锁内的代码片段抽取出来单独声明事务,确保锁释放是在事务提交后进行的
  • 6. 问题(间隙锁—场景描述): 秒杀提交订单为了代码执行效率,把创建易宝订单(对接的第三方支付)的步骤放到了生成本地订单步骤之前。创建易宝订单的代码块是复用的之前普通下单的,所以有对订单的修改操作(用于保存易宝流水号),但因为此时本地订单在数据库中还未生成,所以根据主键的修改操作会产生间隙锁。因为秒杀场景又会有多个线程同时在运行,多个线程同时执行这段代码块,会因为间隙锁导致死锁,这时在锁未释放的时候,再对订单表进行插入操作,则会直接报错(Deadlock found when trying to get lock
    注: 数据库隔离级别为可重复读(REPEATABLE READ)
    解决办法: 这里是对“创建易宝订单”代码块里的保存易宝交易单号信息这段代码进行了非空判断,对本地数据库中不存在的订单不保存相关易宝流水号(可以在易宝后台根据交易订单号获取相关信息)
# 报错信息
### Error updating database.  Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
  • 7. 问题: sql语句中有空值的列使用in或者not in操作会失效
    解决办法:
1. 避免出现空值列(赋予默认值)
2. 用 `or` 连接一个为空的条件 `is null`
例如:column_1 is null or column_1 not in (1,2)
  • 8. 问题: Druid连接池配置开启removeAbandoned: true(强制关闭连接时长大于removeAbandonedTimeoutMillis的数据库连接),并且removeAbandonedTimeoutMillis(连接最大生命周期)设置的时间过短,导致数据库连接被强制关闭。
    报错信息
[ERROR] - com.alibaba.druid.pool.DruidDataSource.removeAbandoned(DruidDataSource.java:2979) - abandon connection, owner thread: xxx, connected at : xxx, open stackTrace

解决办法:

1. 将removeAbandoned这个配置设置为false或者不设置(默认就是false)

或者

2. 将removeAbandonedTimeoutMillis这个时间配置调大
# 时间设置为30分钟(单位:秒)
remove-abandoned-timeout: 1800
# 时间设置为30分钟(单位:毫秒)
remove-abandoned-timeout-millis: 1800000
配置 默认值 说明
removeAbandoned false 是否强制关闭连接时长大于removeAbandonedTimeoutMillis的连接
removeAbandonedTimeoutMillis 300 * 1000 (单位:毫秒) 一个连接从被连接到被关闭之间的最大生命周期
logAbandoned false 强制关闭连接时是否记录日志
  • 9. 问题:三元表达式空指针问题,包装类型自动拆箱,空值null拆箱操作,也就是Integer的intValue()方法报空指针。
        DTO dto = new DTO();
        System.out.println(build != null ? build.getProperty() : 1);

解决办法:

        DTO dto = new DTO();
        System.out.println(build != null ? build.getProperty() : Integer.valueOf(1));
  • 10. 问题:Spring事务默认的传播行为:Propagation.REQUIRED。在使用Spring事务时,在一个事务A中又开了一个事务B(即存在嵌套事务),当事务B发生异常时,在A中将异常catch后事务B会进行回滚操作,此时异常被catch掉,事务A依然会抛出如上异常并进行回滚操作。
    原因一:因为methodB的传播属性设置为PROPAGATION_REQUIRED,PROPAGATION_REQUIRED的意思是,当前有事务,则使用当前事务,当前无事务则创建事务。由于methodA的传播属性也为PROPAGATION_REQUIRED,所以methodA会创建一个事务,然后methodB与methodA使用同一个事务,methodB出现异常后,将当前事务标志位回滚,由于在methodA中做了trycatch处理,程序没有终止而是继续往下走,当事务commit时,check状态,发现,需要事务回滚,所以才会出现不可预知的事务异常:因为事务被标志位回滚,所以事务回滚。
    也就是说:methodA与methodB共用一个事务,methodB将事务标志为回滚,methodA中commit这个事务,然后,出现事务已经被标志回滚(methodB标志的)的异常信息。
    解决办法:
1. methodA与methodB在逻辑上不应该属于同一个事务,那么将methodB的事务传播属性修改为PROPAGATION_REQUIRES_NEW,这样,执行methodB时,会创建一个新的事务,不影响methodA中的事务。

2. 业务A与业务B在业务逻辑上就应该属于同一个事务,但是methodB的失败与否不能影响methodA的事务提交,那么仍然在methodA中try catch methodB,并将methodB设置为PROPAGATION_NESTED,它的意思是,methodB是一个子事务,有一个savepoint,失败时会回滚到savepoint,不影响methodA,如果成功则A、B一起提交,A与B都是一个事务,只是B是一个子事务。

Spring事务报错: org.springframework.transaction.UnexpectedRollbackException

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 227,572评论 6 531
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,071评论 3 414
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 175,409评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,569评论 1 307
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,360评论 6 404
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,895评论 1 321
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,979评论 3 440
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,123评论 0 286
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,643评论 1 333
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,559评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,742评论 1 369
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,250评论 5 356
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,981评论 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,363评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,622评论 1 280
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,354评论 3 390
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,707评论 2 370

推荐阅读更多精彩内容