Hibernate对数据库结构提供了较为完整的封装,Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。而MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架,MyBatis需要使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。在编写比较复杂的动态SQL语句时,Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段,Hibernate就比较困难的实现。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="cn.social.card.mybatis.persistence.SocialSecurityCardMapper" > <resultMap id="BaseResultMap" type="cn.social.card.mybatis.domain.SocialSecurityCard"> <id column="ID" jdbcType="DECIMAL" property="id" /> <result column="PCH" jdbcType="VARCHAR" property="pch" /> <result column="DWBH" jdbcType="VARCHAR" property="dwbh" /> <result column="XM" jdbcType="VARCHAR" property="xm" /> <result column="XB" jdbcType="VARCHAR" property="xb" /> <result column="SFZH" jdbcType="VARCHAR" property="sfzh" /> <result column="SBKH" jdbcType="VARCHAR" property="sbkh" /> <result column="DWMC" jdbcType="VARCHAR" property="dwmc" /> <result column="YHKH" jdbcType="VARCHAR" property="yhkh" /> <result column="SWKZT" jdbcType="VARCHAR" property="swkzt" /> <result column="JSDWLXR" jdbcType="VARCHAR" property="jsdwlxr" /> <result column="JSDWLXDH" jdbcType="VARCHAR" property="jsdwlxdh" /> <result column="DJCKRY" jdbcType="VARCHAR" property="djckry" /> <result column="DJCKLXFS" jdbcType="VARCHAR" property="djcklxfs" /> <result column="DJSSDW" jdbcType="VARCHAR" property="djssdw" /> <result column="CZRY" jdbcType="VARCHAR" property="czry" /> <result column="CZRQ" jdbcType="VARCHAR" property="czrq" /> </resultMap> <select id="findCountByCriteria" resultType="java.lang.Integer" > select count(*) from T_SOCIAL_CARD T1 <include refid="find_where" /> </select> <select id="findPageListByCriteria" resultMap="BaseResultMap"> <include refid="detail_select" /> <include refid="find_where" /> </select> <sql id="find_where"> WHERE 1=1 <if test="param != null"> AND (T1.SFZH LIKE '%'+#{param}+'%' OR T1.XM LIKE '%'+#{param}+'%') </if> </sql> </mapper>
resultMap 需要把一个一个字段配置,如果一个表字段太多了显示很臃肿也很容易配置出错,我们先抛开这个,我们来查看一下Mybatis怎么实现动态的sql的,采用了if、foreach 等标签,在执行SQL语句之前,先解析这些标签。
我们在页面上也有采用模板引擎,内置了很多web编程中很常用的方法(日期转换、数字格式化等)方便开发人员操作。比较常见的是FreeMarker是模板引擎,是一种基于模板的、用来生成输出文本的通用工具,是基于Java的开发包和类库的。我们可以借鉴MyBatis实现思想和采用模板引擎。
在给大家介绍另外一个Velocity,Velocity是一个基于java的模板引擎(templateengine)。它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。它可以从模板(template)产生SQL和PostScript、XML,它也可以被当作一个独立工具来产生源代码和报告,或者作为其他系统的集成组件使用。Velocity也可以为Turbine web开发架构提供模板服务(template service)。
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Mapping file autogenerated by MyEclipse - Hibernate Tools --> <hibernate-mapping package="com.hibernate.model"> <class name="Card" table="t_card"> <id name="id" column="id" type="java.lang.Integer"> <generator class="native"/> </id> <property name="pch" column="pch" type="java.lang.String"/> <property name="dwbh" column="dwbh" type="java.lang.String"/> <property name="xm" column="xm" type="java.lang.String"/> <property name="xb" column="xb" type="java.lang.String"/> <property name="sfzh" column="sfzh" type="java.lang.String"/> <property name="sbkh" column="sbkh" type="java.lang.String"/> <property name="dwmc" column="dwmc" type="java.lang.String"/> <property name="yhkh" column="yhkh" type="java.lang.String"/> </class> <sql-query name="Card.getCards"> <return-scalar column="id" type="java.lang.Integer"/> <return-scalar column="pch" type="java.lang.String"/> <return-scalar column="dwbh" type="java.lang.String"/> <return-scalar column="xm" type="java.lang.String"/> <return-scalar column="xb" type="java.lang.String"/> <return-scalar column="sfzh" type="java.lang.String"/> <![CDATA[ select t.id as id, t.pch as pch, t.dwbh as dwbh, t.xm as xm, t.xb as xb, t.sfzh as sfzh from t_card t where 1=1 #if($xm) and t.xm=:xm #end #if($pch) and t.pch like '%$pch%' #end ]]> </sql-query> </hibernate-mapping>
Velocity 是采用"#"用来标识的,例如#set、#if 、#else、#end、#foreach、#end、#iinclude、#parse、#macro等;
例如:
#if($xm)
and t.xm=:xm
#end
#if($pch)
and t.pch like '%$pch%'
#end
(一)CardDaoImpl
@Repository public class CardDaoImpl extends BaseDaoImpl<Card> implements CardDao { @SuppressWarnings("unchecked") @Override public List<Card> getCards(Map<String, Object> param) { return getNamedQuery("Card.getCards", param).setResultTransformer(Transformers.aliasToBean(Card.class)).list(); } }
(二)BaseDaoImpl
public class BaseDaoImpl<T> implements BaseDao<T> { @Autowired private SessionFactory sessionFactory; public Session getCurrentSession() { return sessionFactory.getCurrentSession(); } @Override public void add(Object entriy) { getCurrentSession().save(entriy); } /** * 设置动态的SQL * @param queryName * @param param * @return */ @SuppressWarnings("rawtypes") public Query getNamedQuery(String queryName,Map<String,Object> param ){ Query query=getCurrentSession().getNamedQuery(queryName); Query rsQuery=null; try { //初始化运行时引擎, 默认初始化 Velocity.init(); //建立context, 并放入数据 VelocityContext context=new VelocityContext(); Set<String> keys=param.keySet(); for (Iterator iterator = keys.iterator(); iterator.hasNext();) { String key = (String) iterator.next(); context.put(key, param.get(key)); } //解析后数据的输出目标,java.io.Writer的子类 StringWriter sql=new StringWriter(); //进行解析 Velocity.evaluate(context, sql, "myQuery", query.getQueryString()); rsQuery=getCurrentSession().createSQLQuery(sql.toString()); } catch (Exception e) { e.printStackTrace(); } setQueryNameParameters(rsQuery,param); return rsQuery; } /** * 设置参数 * @param query * @param param * @return */ public Query setQueryNameParameters(Query query,Map<String,Object> param){ String[] nameParams=query.getNamedParameters(); for(String nameParam:nameParams){ Object obj=param.get(nameParam); if(obj instanceof Collection){ query.setParameterList(nameParam, (Collection)obj); }else if(obj.getClass().isArray()){ query.setParameterList(nameParam, (Object[])obj); }else{ query.setParameter(nameParam,obj); } } return query; } }
是通过Velocity模板和传递进去的parameters参数对模板进行解析,得到最终的语句(纯sql/hql)。
1)获取最原始的SQL语句Query query=getCurrentSession().getNamedQuery(queryName);
2)通过Velocity模板和传递进去的parameters参数对模板进行对标签进行解析,Velocity.evaluate(context, sql, "myQuery", query.getQueryString());
3)然后重新创建成sql/hql语句,rsQuery=getCurrentSession().createSQLQuery(sql.toString());
4)设置参数值,执行返回结果