Grails多线程批量操作

Grails多线程批量操作

多线程使用不当会导致hibernate no session

数据库原数据

9FB125DEEDBC41938DAA348624D30990.png

一个普通的更新服务类

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+"秒。"
    }
}

执行完成

0E48EBED68BA45F5BD6C636243AA2AC2.png

表数据

C6C3F1E9F8D047AB93E371F4E58EAA3F.png

个人认为每个线程都必须有个独立的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+"秒。"
    }

测试结果

8DF8CD98FD744C78BAA021032F608981.png

多线程之所以耗时0.016,是因为程序向下执行,并不回等每个线程执行完成再继续,有点并行的意思,代码向下执行,也许在处理完成之前就打印了时间,所以给人的感觉很快,其实后台还在处理

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

  • 发表于 2018-05-24 10:21
  • 阅读 ( 2074 )
  • 分类:grails

0 条评论

请先 登录 后评论
不写代码的码农
Jonny

程序猿

65 篇文章

作家榜 »

  1. 威猛的小站长 124 文章
  2. Jonny 65 文章
  3. 江南烟雨 36 文章
  4. - Nightmare 33 文章
  5. doublechina 31 文章
  6. HJ社区-肖峰 29 文章
  7. 伪摄影 22 文章
  8. Alan 14 文章