本文简单介绍了体系的开发经验。

1. GORM批量操作

1.1. 批量修改或批量删除

以下示例了如何进行批量操作

//使用where 进行匹配修改
BaseUser.where {
    enable == true
}.updateAll([enable: false])

//使用where 进行匹配删除
BaseUser.where {
    enable == true
}.deleteAll([flush: true])

1.2. 表间数据批量导入

常见的表间数据导入(如 sql是 insert into * select * form *)这种情况建议使用HQL进行操作,可以保持数据库无关系

BaseUser.executeUpdate('''
    INSERT INTO BaseUser(version, username,enable) SELECT 0,name FROM Person person
    WHERE person.isUserActive= :active
''', [active: true])

1.3. 批量新增操作

针对对象级批量新增,因为hibernate会二级缓存数据,会出现操作越来越慢的情况。需要清除hibernate session

1.3.1. 方法1

 BaseUser.withNewSession {session->
            (1..50000).each { num ->
                BaseUser user  = new BaseUser()
                user.username ="user-${num}"
                user.save(flush: true)
                //每100次清除一次缓存
                if(num.mod(100)==0) {
                    session.flush()
                    session.clear()
                }
            }
        }

1.3.2. 方法2

BaseUser.withNewSession {session->
	Transaction tx = session.beginTransaction()
            (1..50000).each { num ->
                BaseUser user  = new BaseUser()
                user.username ="user-${num}"
                session.save(user)
                if(num.mod(100)==0) {
                    session.flush()
                    session.clear()
                }
            }
    tx.commit();
}

1.3.3. 方法3

       @Autowired
        SessionFactory sessionFactory
        //......
        StatelessSession session = sessionFactory.openStatelessSession()
        Transaction tx = session.beginTransaction();
        (1..50000).each { num ->
            BaseUser user  = new BaseUser()
            user.username ="user-${num}"
            session.insert(user)
            if(num.mod(100)==0) {
                session.flush()
                session.clear()
            }
        }
        tx.commit();
        session.close();

2. GORM统计

使用hibernate做统计一直是困难点,GORM对其进行了一定程度的简化,便于理解和使用

2.1. 基本用法

还是使用Domain类的 createCriteria().list{} 闭包来进行操作。

使用如下的基本函数

    projections
    resultTransformer
    createAlias
    property
    groupProperty

还有如下的高级函数

sqlProjection
sqlGroupProjection

2.2. domain类上设置虚拟字段

有些统计字段需要使用虚拟字段来实现,具体用法如下:

使用@Transient
在mapping中使用formula公式

如下示例,在domain类中增加一个根据小时分组的字段

 @Title(zh_CN = "时间")  Timestamp createTime
 @Transient    Integer grouphour
 static mapping = {
        //Postgres使用的时间函数
        grouphour formula: 'extract(hour from create_time)'
        //H2使用的时间函数
        grouphour formula: 'hour(CREATE_TIME)'
    }

2.3. 分组统计查询

List routerList=GatewayMetrics.createCriteria().list{
    resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
    createAlias("router","routerObj",LEFT_OUTER_JOIN.getJoinTypeValue())
    projections{
        sum('successCount','total')
    }
    gt('successCount',0)
    ge('createTime',startDate)
    le('createTime',endDate)
    order("total","desc")
    groupProperty('routerObj.name','routerName')
}

2.4. 使用sqlGroupProjections分组统计

//sqlGroupProjection  postgres函数extract  year,month,day,hour,min,sec
List list = GatewayMetrics.createCriteria ().list{
    projections{
        sqlGroupProjection 'extract(day from create_time) as everyday,sum(success_count) as succtotal',
            'everyday order by everyday asc',['everyday','succtotal'],[INTEGER,INTEGER]
    }
}

2.5. 注意事项

尽量使用resultTransformer转换结果
groupProperty 中的字段不要在使用property出现在projections中

3. Themleaf3 的动态代码

比较复杂的是循环输出的情况

3.1. Body部分页面循环输出

//each 循环输出
<div th:each="node:${nodes}">
    <span th:text='${node.name}'></span>
</div>

3.2. script脚本中循环

script脚本中循环,需要使用[# th:each …​] 输出

//脚本时
<script th:inline="javascript" >
.....
   [# th:each="node,iterStat : ${nodes}"]
	//[# th:text="${node.name}"/]
	var isInsert[# th:text="${iterStat.index}"/] =false ;
	var height[# th:text="${iterStat.index}"/]=[${node.diagramNode.height}+'px'];
    [/]
//.....
</script>