Skip to content

编写数据库操作

luocaihua edited this page Apr 30, 2015 · 1 revision

TranSession用于进行数据库的持久化操作

GuzzBaseDao基类:

guzz建议所有的Dao继承GuzzBaseDao,以使用base dao中提供的常用持久化方法。

但需要注意,在没有配置Spring声明式事务的情况下,GuzzBaseDao 中的每个方法都会在单独的事务中完成;如果需要多个操作原子执行,但又不用spring容器事务,请不要使用GuzzBaseDao提供的方法。 如果声明了spring事务,则GuzzBaseDao内的方法都将在spring统一事务管理下执行;读方法还将单独打开到slave数据库的只读连接执行,不会加入事务。 如果需要执行加入当前写事务的读操作,或执行GuzzBaseDao没有提供的写操作,可以通过 getWriteTemplate()获取当前的WriteTemplate进行事务读写。WriteTemplate类似HibernateTemplate和JDBCTemplate。

GuzzBaseDao 在spring中配置

典型配置:

    <bean id="abstractGuzzDao" class="org.guzz.dao.GuzzBaseDao" abstract="true">
    	<property name="guzzContext" ref="guzzContext" />
    </bean>
&lt;bean id=&quot;abstractNoSpringGuzzDao&quot; class=&quot;org.guzz.dao.GuzzBaseDao&quot; abstract=&quot;true&quot;&gt;
	&lt;property name=&quot;guzzContext&quot; ref=&quot;guzzContext&quot; /&gt;
	&lt;property name=&quot;writeTemplate&quot;&gt;
		&lt;bean class=&quot;org.guzz.transaction.SoloWriteTemplate&quot;&gt;
			&lt;property name=&quot;guzzContext&quot; ref=&quot;guzzContext&quot; /&gt;
		&lt;/bean&gt;
	&lt;/property&gt;
&lt;/bean&gt;</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() ; }

ReadonlyTranSession提供按照检索表达式SearchExpression,SQL语句CompiledSQL,以及guzz.xml中配置的sql语句id进行查询的接口。

SearchExpression:

SearchExpression类似于hibernate中的criteria查询,不过功能没有criteria强大,不过名字容易拼写多了。 SearchExpression 通过 SearchTerm 组织查询条件。

CompiledSQL:

由于SearchExpression不可能无限强大,有时候我们需要直接编写SQL语句进行查询。对于SQL语句查询,guzz将sql语句进行预编译生成CompiledSQL以提高性能,并要求SQL必须先编译成CompiledSQL才能执行。 在编写sql语句时guzz额外支持参数命名和businessName属性名替换,规则和guzz.xml中定义的sql规则相同(@@对象名用来替换表名,@属性名用来替换字段名)。示例如下:
TransactionManager tm = super.getTransactionManager() ;

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() ; }

这段代码通过调用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。示例:
TransactionManager tm = super.getTransactionManager() ;

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() ; }

对于特殊的OR映射,开发者可以实现自己的RowDataLoader。 CompiledSQL为线程安全的对象,对于重复执行的sql,建议将编译好的CompiledSQL缓存以来,避免重复解析。在guzz.xml中定义的sql,在guzz内部就是以CompiledSQL进行存储和管理的。

通过guzz.xml中定义的id查询:

类似ibatis。查看编写格式

  1. 定义sql和映射,映射可以直接引用<business>的域对象名称:
 	<sqlMap dbgroup="default">
<select id="selectUser" orm="user">
select * from @@user
where
@id = :id
</select>
	&lt;select id=&quot;selectUserByName&quot; orm=&quot;user&quot;&gt;
		select id, userName, vip, password from tb_user where userName = :userName
		
		&lt;paramsMapping&gt;
			&lt;map paramName=&quot;userName&quot; propName=&quot;userName&quot; /&gt;
		&lt;/paramsMapping&gt;
	&lt;/select&gt;

	&lt;update id=&quot;updateUserFavCount&quot; orm=&quot;userObjectMap&quot;&gt;
		update @@user set @favCount = favCount + 1
	&lt;/update&gt;

	&lt;select id=&quot;getCount&quot; orm=&quot;user&quot;&gt;
		select 30 as totalCount
	&lt;/select&gt;
	
	&lt;select id=&quot;selectUserByName2&quot; orm=&quot;user&quot; result-class=&quot;java.util.HashMap&quot;&gt;
		select pk, userName, VIP_USER, MyPSW, FAV_COUNT from TB_USER where userName = :userName
	&lt;/select&gt;
	
	&lt;select id=&quot;selectUsers&quot; orm=&quot;userObjectMap&quot;&gt;
		select @id, @name, @vip, @favCount from @@user
	&lt;/select&gt;
	
	&lt;select id=&quot;listCommentsByName&quot; orm=&quot;commentMap&quot;&gt;
		select * from @@commentMap where @userName = :userName
		
		&lt;paramsMapping&gt;
			&lt;map paramName=&quot;userName&quot; propName=&quot;userName&quot; /&gt;
		&lt;/paramsMapping&gt;
	&lt;/select&gt;
			
	&lt;orm id=&quot;userObjectMap&quot; class=&quot;org.guzz.test.UserModel&quot;&gt;
		&lt;result property=&quot;id&quot; column=&quot;pk&quot;/&gt;
	    &lt;result property=&quot;name&quot; column=&quot;userName&quot;/&gt;
	    &lt;result property=&quot;favCount&quot; column=&quot;FAV_COUNT&quot;/&gt;
	    &lt;result property=&quot;vip&quot; column=&quot;VIP_USER&quot;/&gt;
	&lt;/orm&gt;
	
	&lt;orm id=&quot;commentMap&quot; dbgroup=&quot;commentDB&quot; class=&quot;org.guzz.test.Comment&quot; table=&quot;TB_COMMENT&quot; shadow=&quot;org.guzz.test.CommentShadowView&quot;&gt;
		&lt;result property=&quot;id&quot; column=&quot;id&quot; type=&quot;int&quot;/&gt;
	    &lt;result property=&quot;userId&quot; column=&quot;userId&quot; type=&quot;int&quot;/&gt;
	    &lt;result property=&quot;userName&quot; column=&quot;userName&quot; type=&quot;string&quot; /&gt;
	    &lt;result property=&quot;createdTime&quot; column=&quot;createdTime&quot; type=&quot;datetime&quot; /&gt;
	&lt;/orm&gt;
&lt;/sqlMap&gt;

&lt;sqlMap dbgroup=&quot;cargoDB&quot;&gt;
	&lt;select id=&quot;selectCrossSize&quot; orm=&quot;cargo&quot; result-class=&quot;org.guzz.orm.rdms.MyCrossStitch&quot;&gt;
		select name, price, gridNum, size, brand from @@cargo where id &gt; :id
	&lt;/select&gt;
&lt;/sqlMap&gt; 
2. 按照id和参数查询.

调用例子1:listCommentsByName:

	HashMap params = new HashMap() ;
	params.put("userName", "lily") ;
ReadonlyTranSession session = tm.openDelayReadTran() ;
Guzz.setTableCondition(tableCondition) ;
List&lt;Comment&gt; comments = session.list(&quot;listCommentsByName&quot;, params, 1, 20) ;
调用例子2:getCount:
	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") ;
ReadonlyTranSession session = tm.openDelayReadTran() ;
List users2 = session.list(&quot;selectUserByName2&quot;, params, 1, 10) ;

assertNotNull(users2) ;
assertEquals(users2.size(), 1) ;
assertEquals(users2.get(0).getClass(), java.util.HashMap.class) ;
	
//由于orm=&quot;user&quot;的作用,结果HashMap的key为User javabean对象中的属性名,而不是数据库字段名。
java.util.Map u = (Map) users2.get(0) ;
assertTrue(u.containsKey(&quot;favCount&quot;)) ;

程序中拼接SQL语句:

用于在程序中动态拼接sql语句,并执行。
 	ReadonlyTranSession session = tm.openDelayReadTran() ; 
	Guzz.setTableCondition("all") ;
//任意拼接出sql字符串
String sql=&quot;select c.* from (select @id, @name, @storeCount from tb_cargo_book where @price&gt;=:param_price union all select @id, @name, @storeCount from tb_cargo_crossstitch where @price&gt;=:param_price) as c &quot;;

//编译成执行对象。第一个参数&quot;Cargo.class&quot;暗示此sql将要运行的数据库组为存储Cargo对象的数据库组,并指定默认结果构造成Cargo对象返回。
CompiledSQL cs = tm.getCompiledSQLBuilder().buildCompiledSQL(Cargo.class, sql) ; 

//赋予sql语句中的参数&quot;param_price&quot;强类型。类型和price属性相同。	
cs.addParamPropMapping(&quot;param_price&quot;, &quot;price&quot;) ;

//返回前1000个货物。
List&lt;Cargo&gt; cargoes = session.list(cs.bind(&quot;param_price&quot;, 100.00), 1, 1000) ;	

//临时更改返回结果为HashMap类型。 -- 通过设置BindedCompiledSQL的参数
List&lt;HashMap&lt;String, Object&gt;&gt; cargoes2 = session.list(cs.bind(&quot;param_price&quot;, 100.00).setResultClass(java.util.HashMap.class), 1, 1000) ;

//更改默认返回结果为HashMap类型。 -- 通过设置CompiledSQL的属性
cs.setResultClass(java.util.HashMap.class) ;	
List&lt;HashMap&lt;String, Object&gt;&gt; cargoes3 = session.list(cs.bind(&quot;param_price&quot;, 100.00), 1, 1000) ;
List&lt;HashMap&lt;String, Object&gt;&gt; cargoes4 = session.list(cs.bind(&quot;param_price&quot;, 100.00), 2, 20) ;

session.close() ;

WriteTranSession写API

WriteTranSession为写api接口。
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() ;
	for(int loop = 0 ; loop &lt; 1000 ; loop++){
		User user = new User() ;
		user.setUserName(&quot;hello un &quot; + 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, &quot;delete from @@&quot; + User.class.getName() + &quot; where @id = :id&quot;) ;

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,随后按照各自的API添加每次执行的参数,最后执行executeUpdate并提交事务。

注意: 一个Batcher只能用于处理同一领域对象在同一张表的操作,如果需要批量操作多个表的数据,需要创建多个Batcher。

事务一致性:

如果需要执行事务处理,在获取WriteTranSession时需要关闭自动提交事务: tm.openRWTran(false) ; 随后针对此WriteTranSession进行任意操作即可,包括从此WriteTranSession创建JDBCTemplate执行raw sql,或者创建Batcher执行批量操作,在所有操作完成后commit()或者rollback(),guzz将完成多组机器多项操作的分布式事务。