多线程使用不当会导致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,是因为程序向下执行,并不回等每个线程执行完成再继续,有点并行的意思,代码向下执行,也许在处理完成之前就打印了时间,所以给人的感觉很快,其实后台还在处理
此文章仅代表个人观点,并非完全正确,望各位大佬批评指正!