Grails多线程批量操作例子

多线程使用不当会导致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,是因为程序向下执行,并不回等每个线程执行完成再继续,有点并行的意思,代码向下执行,也许在处理完成之前就打印了时间,所以给人的感觉很快,其实后台还在处理

此文章仅代表个人观点,并非完全正确,望各位大佬批评指正!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值