-
Notifications
You must be signed in to change notification settings - Fork 24
编写数据库操作
但需要注意,在没有配置Spring声明式事务的情况下,GuzzBaseDao 中的每个方法都会在单独的事务中完成;如果需要多个操作原子执行,但又不用spring容器事务,请不要使用GuzzBaseDao提供的方法。 如果声明了spring事务,则GuzzBaseDao内的写方法都将在spring统一事务管理下执行;读方法还将单独打开到slave数据库的只读连接执行,不会加入事务。 如果需要执行加入当前写事务的读操作,或执行GuzzBaseDao没有提供的写操作,可以通过 getWriteTemplate()获取当前的WriteTemplate进行事务读写。WriteTemplate类似HibernateTemplate和JDBCTemplate。
典型配置:
<bean id="abstractGuzzDao" class="org.guzz.dao.GuzzBaseDao" abstract="true"> <property name="guzzContext" ref="guzzContext" /> </bean>ReadonlyTranSession提供按照检索表达式SearchExpression,SQL语句CompiledSQL,以及guzz.xml中配置的sql语句id进行查询的接口。 SearchExpression类似于hibernate中的criteria查询,不过功能没有criteria强大,不过名字容易拼写多了。 SearchExpression 通过 SearchTerm 组织查询条件。 由于SearchExpression不可能无限强大,有时候我们需要直接编写SQL语句进行查询。对于SQL语句查询,guzz将sql语句进行预编译生成CompiledSQL以提高性能,并要求SQL必须先编译成CompiledSQL才能执行。 在编写sql语句时guzz额外支持参数命名和businessName属性名替换,规则和guzz.xml中定义的sql规则相同(@@对象名用来替换表名,@属性名用来替换字段名)。示例如下:<bean id="abstractNoSpringGuzzDao" class="org.guzz.dao.GuzzBaseDao" abstract="true"> <property name="guzzContext" ref="guzzContext" /> <property name="writeTemplate"> <bean class="org.guzz.transaction.SoloWriteTemplate"> <property name="guzzContext" ref="guzzContext" /> </bean> </property> </bean></pre> <p>对于需要加入spring事务的dao,bean的parent设置成abstractGuzzDao;对于配置了spring事务,但是不需要加入事务的dao,bean的parent配置成abstractNoSpringGuzzDao。 </p> <h2> <a name="ReadonlyTranSession_读API:"></a>ReadonlyTranSession读API:<a href="#ReadonlyTranSession_读API:" class="section_anchor"></a> </h2> ReadonlyTranSession为guzz对外提供的查询操作入口,获取方法: <pre class="prettyprint">TransactionManager tm = guzzContext.getTransactionManager() ;
ReadonlyTranSession session = getTransactionManager().openDelayReadTran() ;
try{ SearchExpression se = SearchExpression.forClass(SystemLog.class) ; se.and(Terms.eq("categoryId", 18)) ; se.setOrderBy("importance desc, id asc") ; return session.list(se) ; }finally{ session.close() ; }
TransactionManager tm = super.getTransactionManager() ;这段代码通过调用CompiledSQLBuilder的buildCompiledSQL方法编译SQL,其中第一个参数为对象类名,guzz根本此参数判定SQL语句应该在哪个数据库组执行。 上面的示例是更新操作,如果是查询操作,查询到的结果记录集,guzz还会按照参数1传入的类名进行ORM映射,返回的查询结果将会是List < SystemLog > 。 CompiledSQL的使用比较灵活,对于个性化的查询SQL有时候需要个性化的映射关系,guzz默认提供的按照领域对象映射是无法满足全部需求的。 CompiledSQL在执行前通过bind()方法绑定命名参数,生成了一个临时对象BindedCompiledSQL,而我们实际上是使用BindedCompiledSQL进行查询。 BindedCompiledSQL不是线程安全的,只能使用一次,开发时,应用可以在BindedCompiledSQL中设置仅限本次查询有效的参数。 对于个性化的查询SQL有时候需要个性化的映射关系,guzz默认提供的按照领域对象映射是无法满足全部需求的,这时,BindedCompiledSQL就可以用来临时调整某1次查询的ORM--通过BindedCompiledSQL的setRowDataLoader(RowDataLoader)方法替换对象映射关系。guzz默认提供了2个RowDataLoader的实现:FirstColumnDataLoader(只提取第一列数据),FormBeanRowDataLoader(映射结果集到任意一个pojo或Map中)。 RowDataLoader为轻量级对象,对于结果集映射个性处理建议全部通过RowDataLoader。示例:String sql = "update @@" + SystemLog.class.getName() + " set @importance = :level where @id = :id" ; CompiledSQL cs = tm.getCompiledSQLBuilder().buildCompiledSQL(SystemLog.class, sql) ;
WriteTranSession session = tm.openRWTran(true) ;
try{ session.executeUpdate(cs.bind("level", 3).bind("id", 5)) ; }finally{ session.close() ; }
TransactionManager tm = super.getTransactionManager() ;对于特殊的OR映射,开发者可以实现自己的RowDataLoader。 CompiledSQL为线程安全的对象,对于重复执行的sql,建议将编译好的CompiledSQL缓存以来,避免重复解析。在guzz.xml中定义的sql,在guzz内部就是以CompiledSQL进行存储和管理的。 类似ibatis。查看编写格式。String sql = "select count(*) as count, company from mycompany join xxx... where group by company having salary = :salary " ;
CompiledSQL cs = builder.buildCompiledSQL(Company.class, sql) ;
WriteTranSession session = tm.openRWTran(true) ;
try{ //Map the ResultSet to HashMap, bind parameters, and execute the query. List<Map> result = session.list(cs.setRowDataLoader(FormBeanRowDataLoader.newInstanceForClass(HashMap.class)).bind("salary", 3000)) ; }finally{ session.close() ; }
- 定义sql和映射,映射可以直接引用<business>的域对象名称:
<sqlMap dbgroup="default"> <select id="selectUser" orm="user"> select * from @@user where @id = :id </select>2. 按照id和参数查询.<select id="selectUserByName" orm="user"> select id, userName, vip, password from tb_user where userName = :userName <paramsMapping> <map paramName="userName" propName="userName" /> </paramsMapping> </select> <update id="updateUserFavCount" orm="userObjectMap"> update @@user set @favCount = favCount + 1 </update> <select id="getCount" orm="user"> select 30 as totalCount </select> <select id="selectUserByName2" orm="user" result-class="java.util.HashMap"> select pk, userName, VIP_USER, MyPSW, FAV_COUNT from TB_USER where userName = :userName </select> <select id="selectUsers" orm="userObjectMap"> select @id, @name, @vip, @favCount from @@user </select> <select id="listCommentsByName" orm="commentMap"> select * from @@commentMap where @userName = :userName <paramsMapping> <map paramName="userName" propName="userName" /> </paramsMapping> </select> <orm id="userObjectMap" class="org.guzz.test.UserModel"> <result property="id" column="pk"/> <result property="name" column="userName"/> <result property="favCount" column="FAV_COUNT"/> <result property="vip" column="VIP_USER"/> </orm> <orm id="commentMap" dbgroup="commentDB" class="org.guzz.test.Comment" table="TB_COMMENT" shadow="org.guzz.test.CommentShadowView"> <result property="id" column="id" type="int"/> <result property="userId" column="userId" type="int"/> <result property="userName" column="userName" type="string" /> <result property="createdTime" column="createdTime" type="datetime" /> </orm> </sqlMap> <sqlMap dbgroup="cargoDB"> <select id="selectCrossSize" orm="cargo" result-class="org.guzz.orm.rdms.MyCrossStitch"> select name, price, gridNum, size, brand from @@cargo where id > :id </select> </sqlMap>
调用例子1:listCommentsByName:
HashMap params = new HashMap() ; params.put("userName", "lily") ;调用例子2:getCount:ReadonlyTranSession session = tm.openDelayReadTran() ; Guzz.setTableCondition(tableCondition) ; List<Comment> comments = session.list("listCommentsByName", params, 1, 20) ;
ReadonlyTranSession session = tm.openDelayReadTran() ; int totalCount = (Integer) session.findCell00("getCount", null, "int") ; assertEquals(totalCount, 30) ;调用例子3:selectUserByName2:
HashMap params = new HashMap() ; params.put("userName", "name 1") ;用于在程序中动态拼接sql语句,并执行。ReadonlyTranSession session = tm.openDelayReadTran() ; List users2 = session.list("selectUserByName2", params, 1, 10) ; assertNotNull(users2) ; assertEquals(users2.size(), 1) ; assertEquals(users2.get(0).getClass(), java.util.HashMap.class) ; //由于orm="user"的作用,结果HashMap的key为User javabean对象中的属性名,而不是数据库字段名。 java.util.Map u = (Map) users2.get(0) ; assertTrue(u.containsKey("favCount")) ;
ReadonlyTranSession session = tm.openDelayReadTran() ; Guzz.setTableCondition("all") ;WriteTranSession为写api接口。//任意拼接出sql字符串 String sql="select c.* from (select @id, @name, @storeCount from tb_cargo_book where @price>=:param_price union all select @id, @name, @storeCount from tb_cargo_crossstitch where @price>=:param_price) as c "; //编译成执行对象。第一个参数"Cargo.class"暗示此sql将要运行的数据库组为存储Cargo对象的数据库组,并指定默认结果构造成Cargo对象返回。 CompiledSQL cs = tm.getCompiledSQLBuilder().buildCompiledSQL(Cargo.class, sql) ; //赋予sql语句中的参数"param_price"强类型。类型和price属性相同。 cs.addParamPropMapping("param_price", "price") ; //返回前1000个货物。 List<Cargo> cargoes = session.list(cs.bind("param_price", 100.00), 1, 1000) ; //临时更改返回结果为HashMap类型。 -- 通过设置BindedCompiledSQL的参数 List<HashMap<String, Object>> cargoes2 = session.list(cs.bind("param_price", 100.00).setResultClass(java.util.HashMap.class), 1, 1000) ; //更改默认返回结果为HashMap类型。 -- 通过设置CompiledSQL的属性 cs.setResultClass(java.util.HashMap.class) ; List<HashMap<String, Object>> cargoes3 = session.list(cs.bind("param_price", 100.00), 1, 1000) ; List<HashMap<String, Object>> cargoes4 = session.list(cs.bind("param_price", 100.00), 2, 20) ; session.close() ;
TransactionManager tm = super.getTransactionManager() ; WriteTranSession session = tm.openRWTran(true) ;在获取时,传入参数是否自动提交事务。true:自动提交;false:手动提交。 如果设置为false,在这执行完操作后,需要调用session.commit()或者session.rollback()结束事务。 WriteTranSession只允许通过主键进行查询操作,查询时从主数据库操作。其他方法与ReadonlyTranSession用法类似。
guzz提供两种批量操作接口,一种基于对象,一种基于SQL语句。执行批量操作,需要首先获取WriteTranSession。
基于对象:
WriteTranSession session = tm.openRWTran(false) ; ObjectBatcher batcher = session.createObjectBatcher() ;两种方式都需要首先打开写事务连接,创建Batcher,随后按照各自的API添加每次执行的参数,最后执行executeUpdate并提交事务。for(int loop = 0 ; loop < 1000 ; loop++){ User user = new User() ; user.setUserName("hello un " + i) ; batcher.insert(user) ; } batcher.executeUpdate() ; session.commit() ; session.close() ;</pre> <p> <strong>基于SQL语句: </strong> </p> <pre class="prettyprint">CompiledSQL cs = tm.getCompiledSQLBuilder().buildCompiledSQL(User.class, "delete from @@" + User.class.getName() + " where @id = :id") ;
WriteTranSession session = tm.openRWTran(false) ; SQLBatcher batcher = session.createCompiledSQLBatcher(cs) ;
for(int loop = 0 ; loop < 100 ; loop++){ batcher.addNewBatchParams("id", user.getId()) ; }
batcher.executeUpdate() ; session.commit() ;
注意: 一个Batcher只能用于处理同一领域对象在同一张表的操作,如果需要批量操作多个表的数据,需要创建多个Batcher。
如果需要执行事务处理,在获取WriteTranSession时需要关闭自动提交事务: tm.openRWTran(false) ; 随后针对此WriteTranSession进行任意操作即可,包括从此WriteTranSession创建JDBCTemplate执行raw sql,或者创建Batcher执行批量操作,在所有操作完成后commit()或者rollback(),guzz将完成多组机器多项操作的分布式事务。