工作中遇到的问题与处理

记录一下工作中遇到的问题及解决方式:

1、在后台,执行事务时,遇到了锁等待超时,导致方法执行失败,所有操作回滚。

报错内容:
Lock wait timeout exceeded; try restarting transaction
原因:
事务中有一个insert方法,在执行的时候,遇到了锁,但是又因为锁需要事务提交后才能释放,但insert方法也在同一个事务中,即insert执行后,锁才能释放,但锁不先释放,insert就无法执行。所以最后导致锁等待超时。
当时的事务级别是 可重复读(REPEATABLE_READ)(mysql默认):

  • 读事务禁止其他写事务(但允许其他读事务),未提交的写事务禁止其他读事务和写事务。
  • 此隔离级别可以防止更新丢失、脏读、不可重复读,但不能防止幻读。
  • 此隔离级别可以通过“共享读锁”和“排他写锁”实现。

解决方案:

  1. 修改最外层方法的事务级别。 因为当前方法有嵌套,父方法调用了两个子方法,所以结果并没有作用。因为子方法,会执行它自己的事务级别。要想通过修改事务级别来尝试能不能解决锁问题,就要细化到内部具体导致锁的那个子方法上,修改那里的事务级别。但内方法其他模块也调用到,这样修改会对其他模块造成影响。修改代价大。
  2. 可以根据事务传播机制,设置被调用的内部方法执行自己的事务,而不加入到最上级的事务中。
    但是这样,由于前面已经提交过了内部的子事务,那内部另外的子事务、或者外部的大事务异常了,还能回滚已提交的那个内部子事务吗?
    答:不可以。已经提交了的就是提交了,不可能再回滚。事务最终结果只有提交或回滚。
  3. 将最上层的事务拆分成两个,锁放在一个事务,insert方法放在另一个事务。再分别调用两个方法。 这样,就不会互相影响。
    但有弊端,就是如果前面事务成功,后面事务失败,则只能回滚后面的事务。
    加入一点逻辑改变。第一个事务执行完成后,不提交,而返回一个标识到下一个事务,等到第二个事务成功提交后,再返回第一个事务进行提交。
    这种做法可以实现业务异常上的回滚。而对于数据库上的异常(如insert插入失败等)在异常捕获的时候,回滚,并记录异常,同时开启一个线程,来重新执行该操作。

最终采取方案:
采用方案2。

2、后台保存到mysql时,中文乱码,显示???

报错内容:(无)
原因: 后台数据正常,mysql数据库编码设置正常(show variables like "character_set_%"查看character_set_database、character_set_client),数据库中文数据能够正常返回。所以保存数据库的过程中,前、后都是正常的,那问题就出在数据库连接上。
解决方案: 数据库连接的 url 上,加上 ?useUnicode=true&characterEncoding=utf-8 。设置连接保存utf-8编码

3、hibernate:

描述: 调用getHibernateTemplate(),在方法中进行多个的更新、删除操作的时候,只能执行几条数据,大多无法执行。
原因: 同一个事务内部,调用多次template操作,只会执行最后的一次调用。可能是因为该部分的sql缓存不断更新,而不是新增,导致只有最后加入到缓存的sql能够被执行,而其他的都被最后一次的sql替换了。
解决方法: 在那部分的每个 template的操作后面调用 flush(清除缓存,执行SQL)。
注意:就算调用了flush,强制刷新了sql,但事务依然有效,无需改动

4、tomcat的内存溢出:

如果是 OutOfMemoryError: Java heap space 或者 OutOfMemoryError: PermGen space 应用本身没有内存泄露的情况下可以用设置tomcat jvm参数来解决:

Linux服务器:
在/bin 目录下的catalina.sh
添加:JAVA_OPTS='-Xms512m -Xmx1024m'
或者:JAVA_OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m"
或者:CATALINA_OPTS="-server -Xms256m -Xmx300m"

Windows服务器:
在catalina.bat最前面加入
set JAVA_OPTS=-Xms128m -Xmx350m
或者set CATALINA_OPTS=-Xmx300M -Xms256M
(区别是一个直接设置jvm内存, 另一个设置tomcat内存,CATALINA_OPTS似乎可以与JAVA_OPTS不加区别的使用)

注:
-Xms:初始堆大小
-Xmx:最大堆大小

第三种内存溢出:OutOfMemoryError: unable to create new native thread
可能需要调整操作系统和tomcat jvm参数同时调整才能达到目的。
5、在同一个事务中,有个子方法调用了hibernate的get获取实体,方法是void没有返回值。然后在外面的方法里,也get了一次实体,但是获取到的内容有异常,也不能update。

原因: 在更新前,获取数据的时候,在另一个子方法里也获取到了,但是子方法没有返回,导致重新获取实体失败。
解决: 在子方法加上返回(return null)代表子方法内实体调用结束,后续大方法下就可以重新获取到了

6、界面乱码问题:

描述: 数据库保存数据正常,前端展示时乱码。
tomcat已经配置好utf-8,所以前端应该是没问题的。查询后台返回数据的问题,检查到查询出来的数据库数据就已经是乱码了。但数据库保存的字段又是正常的。
所以要么是查询方式有问题,要么是数据库字段有问题。
而查询方法都是一致的,其他地方没问题,这里却有问题,应该是这里的特殊性导致。
而这里的特殊性就是,字段值里面有中文,且字段类型是json。
所以修改字段类型,改为正常的字符串类型。解决。
原因: 数据库用json保存,然后json内容里,key是中文。导致保存中文成功,但是获取失败。(获取也是跟一般的字段值一样获取)
解决: 修改字段类型为 text或varchar等即可。

7、多线程使用到事务时,报错:

描述: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
原因: 因为getCurrentSession只获取当前线程的session。多线程情况下,当前线程不明确,所以获取currentSession会出错。
解决: 改为获取openSession即可。openSession需要手动关闭,在获取session的地方加入修改。

  1. 先判断当前是否线程下获取session。如果是,则将openSession绑定到当前。
  2. 以获取currentSession的方式获取到openSession。
  3. 关闭session。

eg:

//绑定session到当前线程
public  boolean bindHibernateSessionToThread(SessionFactory sessionFactory) {  
	    if (TransactionSynchronizationManager.hasResource(sessionFactory)) {  
	        return true;  
	    } else {  
	        Session session = sessionFactory.openSession();  
//	        session.setFlushMode(FlushMode.MANUAL);
	        session.setFlushMode(FlushMode.AUTO);
	        SessionHolder sessionHolder = new SessionHolder(session);
	        TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);  
	    }  
	    return false;  
	}  
//获取当前线程session
Session session = getHibernateTemplate().getSessionFactory().getCurrentSession();
//移除绑定session
	public  void closeHibernateSessionFromThread(boolean participate, Object sessionFactory) {  
	    if (!participate) {  
	        SessionHolder sessionHolder = (SessionHolder)TransactionSynchronizationManager.unbindResource(sessionFactory);  
	        SessionFactoryUtils.closeSession(sessionHolder.getSession());  
	    }  
	} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值