多线程使用不当会导致hibernate no session
数据库原数据
一个普通的更新服务类
package com.test import grails.transaction.Transactional @Transactional class TestService { def update(Test t) { t.name = t.name+"BAK" t.title = t.title+"BAK" t.save(flush:true) } }
控制器核心代码
package teststs import com.test.Test class TestController { def testService /** * 批量更新 */ def batchUpdate() { def start = System.currentTimeMillis() def max = 500 new Thread(new Runnable() { public void run() { Test.withTransaction { def tests = Test.list([offset: 0, max: max]) tests.each { testService.update(it) } } } }).start() new Thread(new Runnable() { public void run() { Test.withTransaction { def tests = Test.list([offset: 501, max: max]) tests.each { testService.update(it) } } } }).start() def end = System.currentTimeMillis() def time = (end-start)/1000 render "耗时:"+time+"秒。" } }
执行完成
表数据
个人认为每个线程都必须有个独立的session,所以在每个线程中都要用独立的domain.withTransaction
批量保存
@Transactional
def batchSave() {
def start = System.currentTimeMillis()
(0..2000).eachWithIndex {i,index->
new TestBak(bakTitle: "title${index+1}",bakName: "测试${index+1}").save(flush:true)
}
def end = System.currentTimeMillis()
def time = (end-start)/1000
render "耗时:"+time+"秒。"
}
def batchSave1() {
def start = System.currentTimeMillis()
new Thread(new Runnable() {
public void run() {
Test.withTransaction {
(0..2000).eachWithIndex { i, index ->
new TestBak(bakTitle: "title${index+1}",bakName: "测试${index+1}").save(flush:true)
}
}
}
}).start()
new Thread(new Runnable() {
public void run() {
Test.withTransaction {
(0..2000).eachWithIndex { i, index ->
new TestBak(bakTitle: "title${index+1}",bakName: "测试${index+1}").save(flush:true)
}
}
}
}).start()
new Thread(new Runnable() {
public void run() {
Test.withTransaction {
(0..2000).eachWithIndex { i, index ->
new TestBak(bakTitle: "title${index+1}",bakName: "测试${index+1}").save(flush:true)
}
}
}
}).start()
new Thread(new Runnable() {
public void run() {
Test.withTransaction {
(0..2000).eachWithIndex { i, index ->
new TestBak(bakTitle: "title${index+1}",bakName: "测试${index+1}").save(flush:true)
}
}
}
}).start()
def end = System.currentTimeMillis()
def time = (end-start)/1000
render "耗时:"+time+"秒。"
}
测试结果
多线程之所以耗时0.016,是因为程序向下执行,并不回等每个线程执行完成再继续,有点并行的意思,代码向下执行,也许在处理完成之前就打印了时间,所以给人的感觉很快,其实后台还在处理
此文章仅代表个人观点,并非完全正确,望各位大佬批评指正!
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!