via: http://blog.csdn.net/crazycoder2010/article/details/7414152
1.功能需求背景
项目中使用hibernate作为数据持久层框架,主要考虑hibernate在进行一些简单的crud操作时非常便利,不需要和ibatis似的为每个sql操作都写一堆文件,但是同时也带来了一些局限性,如类似ibatis强大的动态查询功能用不了了,但是这个功能在项目中的应用场景又很大,hibernate自身也支持将sql/hql语句写在.hbm.xml映射文件中<sql-query>和<query>元素,但是这个功能只能对那些查询限制条件固定的sql有用,对于需要动态拼接的sql语句,hibernate就显得力不从心了,如何给hibernate插上ibatis动态查询的翅膀,既保留crud的简洁性,又能收获ibatis的特性呢?接下来的文章将会重点介绍
2.设计思路
先看一下ibatis的动态查询时怎么做的
<select id="getUserList" resultMap="user">
select * from user
<isGreaterThan prepend="and" property="id" compareValue="0">
where user_id = #userId#
</isGreaterThan>
order by createTime desc
</select>
ibatis在程序实现内部回去解析sql语句中的标签,然后去解析计算,我们在ibatis在实现的时候也参考了这个解决思路,但是否是需要把ibatis里的解析sql的语法都抄到我们的dao框架中呢-显然这样太复杂了,而且ibatis自己的sql元素是和那些resultMap等是绑定在一起用的,而在hibernate是没用这些东西的,要改造这些东西是一项非常浩大的工程,因此这个方案被放弃了
我们在实现的时候采取了一种非常简洁又功能强大的方式-模板技术!对,就是利用freemarker把sql/hql中的动态拼接条件判断语法都交给freemarker语法去处理,这样既能复用freemarker框架,又保持了我们框架设计的简洁性-不需要自己写过多的处理逻辑,以下是我们需要进行动态处理的sql/hql语句的样例
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE dynamic-hibernate-statement PUBLIC "-//Haier/HOP Hibernate Dynamic Statement DTD 1.0//EN"
- "http://www.haier.com/dtd/dynamic-hibernate-statement-1.0.dtd">
- <dynamic-hibernate-statement>
- <!-- 查询某个资源下的直接子节点 -->
- <hql-query name="resource.getChildren">
- <![CDATA[
- from Resource where parent.id=${parentId} and parent.id != id
- ]]>
- </hql-query>
- <!-- 查询系统中所有的root资源 -->
- <hql-query name="resource.getRoots">
- <![CDATA[
- from Resource where parent.id = id order by orderIndex
- ]]>
- </hql-query>
- <!-- 获取某个用户可访问的某个资源下的所有子资源 -->
- <sql-query name="resource.getDescendants">
- <![CDATA[
- select distinct t.id,
- t.name,
- t.description,
- t.url,
- t.type,
- t.status,
- t.code,
- t.configuration,
- t.module_name,
- t.gmt_create,
- t.gmt_modified,
- t.create_by,
- t.last_modified_by,
- t.order_index,
- t.parent_id
- from resource_info t
- inner join role_resource rr
- on t.id = rr.resource_id
- inner join user_role ur
- on rr.role_id = ur.role_id
- where ur.user_id = ${userId}
- <#if type == '1'>
- and t.type=1
- <#else>
- and t.type=0
- </#if>
- and t.type = ${type}
- and t.status = ${status}
- start with t.code = '${code}'
- connect by nocycle prior t.id = t.parent_id
- ]]>
- </sql-query>
- </dynamic-hibernate-statement>
这个文件看起来非常类似ibatis的语句了,只是没用ibatis的哪些标签-改成了freemarker语法,没错,我们就是复用freemarker来帮我们解决这些烦杂的判断操作的
这样我们的动态sql程序就可以总结成以下流程
a.系统加载阶段
这个阶段程序负责将指定路径下的动态sql文件加载到内存中,一次性缓存起来,没错,这些东西只需要加载一次,以后直接读取就行了,没必要每次去查找,缓存也非常简单,一个Map<String,String>就搞定,key是sql-query或hql-query元素的name属性,value就是与其对应的sql/hql语句
b.程序调用查询阶段
调用程序通过sql/hql语句的name属性和传入查询参数来得到最终解析出来的语句
我们期望的方法可能是这样的:
- public <X> List<X> findByNamedQuery(final String queryName, final Map<String, ?> parameters)
通过queryName从缓存中查找出其对应的sql/hql语句(最原始的,里面带有freemarker语法)
然后通过freemarker模板和传递进去的parameters参数对模板进行解析,得到最终的语句(纯sql/hql)
最后将解析后的sql/hql传递给底层api,返回查询结果
3.实现
上面介绍了大致的思路,这里介绍具体的代码实现
3.1DTD定义
我们是把动态的sql/hql语句放在单独的xml配置文件里的,为了规范xml文档,我们给文档定义了dtd文件,这里我们只定义了两个元素<sql-query>和<hql-query>分别表示sql查询语句和hql查询语句,这两个元素目前自有一个name属性用来唯一标示该语句,如下
- <!-- HOP Hibernate Dynamic Statement Mapping DTD.
- <!DOCTYPE dynamic-hibernate-statement PUBLIC
- "-//Haier/HOP Hibernate Dynamic Statement DTD 1.0//EN"
- "http://www.haier.com/dtd/dynamic-hibernate-statement-1.0.dtd">
- 这个文件时用来定义动态参数语句,类似itabis
- -->
- <!--
- The document root.
- -->
- <!ELEMENT dynamic-hibernate-statement (
- (hql-query|sql-query)*
- )>
- <!-- default: none -->
- <!-- The query element declares a named Hibernate query string -->
- <!ELEMENT hql-query (#PCDATA)>
- <!ATTLIST hql-query name CDATA #REQUIRED>
- <!-- The sql-query element declares a named SQL query string -->
- <!ELEMENT sql-query (#PCDATA)>
- <!ATTLIST sql-query name CDATA #REQUIRED>
然后将其保存为dynamic-hibernate-statement-1.0.dtd,放在classpath下
编写DTD校验器
- /**
- * hibernate动态sql dtd解析器
- * @author WangXuzheng
- *
- */
- public class DynamicStatementDTDEntityResolver implements EntityResolver, Serializable{
- private static final long serialVersionUID = 8123799007554762965L;
- private static final Logger LOGGER = LoggerFactory.getLogger( DynamicStatementDTDEntityResolver.class );
- private static final String HOP_DYNAMIC_STATEMENT = "http://www.haier.com/dtd/";
- public InputSource resolveEntity(String publicId, String systemId) {
- InputSource source = null; // returning null triggers default behavior
- if ( systemId != null ) {
- LOGGER.debug( "trying to resolve system-id [" + systemId + "]" );
- if ( systemId.startsWith( HOP_DYNAMIC_STATEMENT ) ) {
- LOGGER.debug( "recognized hop dyanmic statement namespace; attempting to resolve on classpath under com/haier/openplatform/dao/hibernate/" );
- source = resolveOnClassPath( publicId, systemId, HOP_DYNAMIC_STATEMENT );
- }
- }
- return source;
- }
- private InputSource resolveOnClassPath(String publicId, String systemId, String namespace) {
- InputSource source = null;
- String path = "com/haier/openplatform/dao/hibernate/" + systemId.substring( namespace.length() );
- InputStream dtdStream = resolveInHibernateNamespace( path );
- if ( dtdStream == null ) {
- LOGGER.debug( "unable to locate [" + systemId + "] on classpath" );
- if ( systemId.substring( namespace.length() ).indexOf( "2.0" ) > -1 ) {
- LOGGER.error( "Don't use old DTDs, read the Hibernate 3.x Migration Guide!" );
- }
- }
- else {
- LOGGER.debug( "located [" + systemId + "] in classpath" );
- source = new InputSource( dtdStream );
- source.setPublicId( publicId );
- source.setSystemId( systemId );
- }
- return source;
- }
- protected InputStream resolveInHibernateNamespace(String path) {
- return this.getClass().getClassLoader().getResourceAsStream( path );
- }
- protected InputStream resolveInLocalNamespace(String path) {
- try {
- return ConfigHelper.getUserResourceAsStream( path );
- }
- catch ( Throwable t ) {
- return null;
- }
- }
- }
3.2编写sql文件
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE dynamic-hibernate-statement PUBLIC "-//Haier/HOP Hibernate Dynamic Statement DTD 1.0//EN"
- "http://www.haier.com/dtd/dynamic-hibernate-statement-1.0.dtd">
- <dynamic-hibernate-statement>
- <!-- 查询某个资源下的直接子节点 -->
- <hql-query name="resource.getChildren">
- <![CDATA[
- from Resource where parent.id=${parentId} and parent.id != id
- ]]>
- </hql-query>
- <!-- 查询系统中所有的root资源 -->
- <hql-query name="resource.getRoots">
- <![CDATA[
- from Resource where parent.id = id order by orderIndex
- ]]>
- </hql-query>
- <!-- 获取某个用户可访问的某个资源下的所有子资源 -->
- <sql-query name="resource.getDescendants">
- <![CDATA[
- select distinct t.id,
- t.name,
- t.description,
- t.url,
- t.type,
- t.status,
- t.code,
- t.configuration,
- t.module_name,
- t.gmt_create,
- t.gmt_modified,
- t.create_by,
- t.last_modified_by,
- t.order_index,
- t.parent_id
- from resource_info t
- inner join role_resource rr
- on t.id = rr.resource_id
- inner join user_role ur
- on rr.role_id = ur.role_id
- where ur.user_id = ${userId}
- <#if type == '1'>
- and t.type=1
- <#else>
- and t.type=0
- </#if>
- and t.type = ${type}
- and t.status = ${status}
- start with t.code = '${code}'
- connect by nocycle prior t.id = t.parent_id
- ]]>
- </sql-query>
- </dynamic-hibernate-statement>
3.3加载动态sql文件
这里我们将加载sql/hql语句的程序独立到一个单独的类中,以便独立扩展
这里一共3个方法,分表标示获取系统中sql/hql语句的map(key:语句名称,value:具体的)
- /**
- * 动态sql/hql语句组装器
- * @author WangXuzheng
- *
- */
- public interface DynamicHibernateStatementBuilder {
- /**
- * hql语句map
- * @return
- */
- public Map<String,String> getNamedHQLQueries();
- /**
- * sql语句map
- * @return
- */
- public Map<String,String> getNamedSQLQueries();
- /**
- * 初始化
- * @throws IOException
- */
- public void init() throws IOException;
- }
默认的加载器-将指定配置文件中的sql/hql语句加载到内存中
- /**
- * @author WangXuzheng
- *
- */
- public class DefaultDynamicHibernateStatementBuilder implements DynamicHibernateStatementBuilder, ResourceLoaderAware {
- private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDynamicHibernateStatementBuilder.class);
- private Map<String, String> namedHQLQueries;
- private Map<String, String> namedSQLQueries;
- private String[] fileNames = new String[0];
- private ResourceLoader resourceLoader;
- private EntityResolver entityResolver = new DynamicStatementDTDEntityResolver();
- /**
- * 查询语句名称缓存,不允许重复
- */
- private Set<String> nameCache = new HashSet<String>();
- public void setFileNames(String[] fileNames) {
- this.fileNames = fileNames;
- }
- @Override
- public Map<String, String> getNamedHQLQueries() {
- return namedHQLQueries;
- }
- @Override
- public Map<String, String> getNamedSQLQueries() {
- return namedSQLQueries;
- }
- @Override
- public void init() throws IOException {
- namedHQLQueries = new HashMap<String, String>();
- namedSQLQueries = new HashMap<String, String>();
- boolean flag = this.resourceLoader instanceof ResourcePatternResolver;
- for (String file : fileNames) {
- if (flag) {
- Resource[] resources = ((ResourcePatternResolver) this.resourceLoader).getResources(file);
- buildMap(resources);
- } else {
- Resource resource = resourceLoader.getResource(file);
- buildMap(resource);
- }
- }
- //clear name cache
- nameCache.clear();
- }
- @Override
- public void setResourceLoader(ResourceLoader resourceLoader) {
- this.resourceLoader = resourceLoader;
- }
- private void buildMap(Resource[] resources) throws IOException {
- if (resources == null) {
- return;
- }
- for (Resource resource : resources) {
- buildMap(resource);
- }
- }
- @SuppressWarnings({ "rawtypes" })
- private void buildMap(Resource resource) {
- InputSource inputSource = null;
- try {
- inputSource = new InputSource(resource.getInputStream());
- XmlDocument metadataXml = MappingReader.INSTANCE.readMappingDocument(entityResolver, inputSource,
- new OriginImpl("file", resource.getFilename()));
- if (isDynamicStatementXml(metadataXml)) {
- final Document doc = metadataXml.getDocumentTree();
- final Element dynamicHibernateStatement = doc.getRootElement();
- Iterator rootChildren = dynamicHibernateStatement.elementIterator();
- while (rootChildren.hasNext()) {
- final Element element = (Element) rootChildren.next();
- final String elementName = element.getName();
- if ("sql-query".equals(elementName)) {
- putStatementToCacheMap(resource, element, namedSQLQueries);
- } else if ("hql-query".equals(elementName)) {
- putStatementToCacheMap(resource, element, namedHQLQueries);
- }
- }
- }
- } catch (Exception e) {
- LOGGER.error(e.toString());
- throw new SysException(e);
- } finally {
- if (inputSource != null && inputSource.getByteStream() != null) {
- try {
- inputSource.getByteStream().close();
- } catch (IOException e) {
- LOGGER.error(e.toString());
- throw new SysException(e);
- }
- }
- }
- }
- private void putStatementToCacheMap(Resource resource, final Element element, Map<String, String> statementMap)
- throws IOException {
- String sqlQueryName = element.attribute("name").getText();
- Validate.notEmpty(sqlQueryName);
- if (nameCache.contains(sqlQueryName)) {
- throw new SysException("重复的sql-query/hql-query语句定义在文件:" + resource.getURI() + "中,必须保证name的唯一.");
- }
- nameCache.add(sqlQueryName);
- String queryText = element.getText();
- statementMap.put(sqlQueryName, queryText);
- }
- private static boolean isDynamicStatementXml(XmlDocument xmlDocument) {
- return "dynamic-hibernate-statement".equals(xmlDocument.getDocumentTree().getRootElement().getName());
- }
- }
配置一下
- <bean id="dynamicStatementBuilder" class="com.haier.openplatform.dao.hibernate.support.DefaultDynamicHibernateStatementBuilder">
- <property name="fileNames">
- <list>
- <value>classpath*:/**/*-dynamic.xml</value><!--这里我们指定要加载某个文件夹下所有以-dynamic.xml结尾的文件 -->
- </list>
- </property>
- </bean>
- <bean id="baseHibernateDAO" class="com.haier.openplatform.dao.hibernate.BaseDAOHibernateImpl" abstract="true">
- <property name="sessionFactory">
- <ref bean="sessionFactory"/>
- </property>
- <property name="dynamicStatementBuilder" ref="dynamicStatementBuilder"/>
- </bean>
dao层代码
- /**
- * Hibernate实现的DAO层
- * @param <T> DAO操作的对象类型
- * @param <ID> 主键类型
- * @author WangXuzheng
- *
- */
- public class SimpleHibernateDAO<T,ID extends Serializable> implements BaseDAO<T, ID>,InitializingBean{
- private static final Logger LOGER = LoggerFactory.getLogger(SimpleHibernateDAO.class);
- protected SessionFactory sessionFactory;
- protected Class<T> entityClass;
- /**
- * 模板缓存
- */
- protected Map<String, StatementTemplate> templateCache;
- protected DynamicHibernateStatementBuilder dynamicStatementBuilder;
- /**
- * 通过子类的泛型定义取得对象类型Class.
- * eg.
- * public class UserDao extends SimpleHibernateDao<User, Long>
- */
- public SimpleHibernateDAO() {
- this.entityClass = Reflections.getSuperClassGenricType(getClass());
- }
- /**
- * 取得sessionFactory.
- */
- public SessionFactory getSessionFactory() {
- return sessionFactory;
- }
- /**
- * 采用@Autowired按类型注入SessionFactory, 当有多个SesionFactory的时候在子类重载本函数.
- */
- public void setSessionFactory(final SessionFactory sessionFactory) {
- this.sessionFactory = sessionFactory;
- }
- public void setDynamicStatementBuilder(DynamicHibernateStatementBuilder dynamicStatementBuilder) {
- this.dynamicStatementBuilder = dynamicStatementBuilder;
- }
- /**
- * 取得当前Session.
- */
- public Session getSession() {
- return sessionFactory.getCurrentSession();
- }
- /**
- * 保存新增或修改的对象.
- */
- @Override
- public void save(final T entity) {
- Validate.notNull(entity, "entity不能为空");
- getSession().save(entity);
- LOGER.debug("save entity: {}", entity);
- }
- /**
- * 删除对象.
- *
- * @param entity 对象必须是session中的对象或含id属性的transient对象.
- */
- @Override
- public void delete(final T entity) {
- if(entity == null){
- return;
- }
- getSession().delete(entity);
- LOGER.debug("delete entity: {}", entity);
- }
- /**
- * 按id删除对象.
- */
- @Override
- public void delete(final ID id) {
- Validate.notNull(id, "id不能为空");
- delete(get(id));
- LOGER.debug("delete entity {},id is {}", entityClass.getSimpleName(), id);
- }
- /**
- * 按id获取对象.
- */
- @SuppressWarnings("unchecked")
- @Override
- public T get(final ID id) {
- Validate.notNull(id, "id不能为空");
- return (T) getSession().get(entityClass, id);
- }
- /**
- * 按id列表获取对象列表.
- */
- public List<T> get(final Collection<ID> ids) {
- return find(Restrictions.in(getIdName(), ids));
- }
- /**
- * 获取全部对象.
- */
- @Override
- public List<T> getAll() {
- return find();
- }
- /**
- * 获取全部对象, 支持按属性行序.
- */
- @SuppressWarnings("unchecked")
- public List<T> getAll(String orderByProperty, boolean isAsc) {
- Criteria c = createCriteria();
- if (isAsc) {
- c.addOrder(Order.asc(orderByProperty));
- } else {
- c.addOrder(Order.desc(orderByProperty));
- }
- return c.list();
- }
- /**
- * 按属性查找对象列表, 匹配方式为相等.
- */
- public List<T> findBy(final String propertyName, final Object value) {
- Criterion criterion = Restrictions.eq(propertyName, value);
- return find(criterion);
- }
- /**
- * 按属性查找唯一对象, 匹配方式为相等.
- */
- @SuppressWarnings("unchecked")
- @Override
- public T findUniqueBy(final String propertyName, final Object value) {
- Criterion criterion = Restrictions.eq(propertyName, value);
- return ((T) createCriteria(criterion).uniqueResult());
- }
- /**
- * 按HQL查询对象列表.
- *
- * @param values 数量可变的参数,按顺序绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> List<X> findByHQL(final String hql, final Object... values) {
- return createHQLQuery(hql, values).list();
- }
- /**
- * 按HQL查询对象列表,并将对象封装成指定的对象
- *
- * @param values 数量可变的参数,按顺序绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> List<X> findByHQLRowMapper(RowMapper<X> rowMapper,final String hql, final Object... values) {
- Validate.notNull(rowMapper, "rowMapper不能为空!");
- List<Object[]> result = createHQLQuery(hql, values).list();
- return buildListResultFromRowMapper(rowMapper, result);
- }
- protected <X> List<X> buildListResultFromRowMapper(RowMapper<X> rowMapper, List<Object[]> result) {
- List<X> rs = new ArrayList<X>(result.size());
- for(Object[] obj : result){
- rs.add(rowMapper.fromColumn(obj));
- }
- return rs;
- }
- /**
- * 按SQL查询对象列表.
- *
- * @param values 数量可变的参数,按顺序绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> List<X> findBySQLRowMapper(RowMapper<X> rowMapper,final String sql, final Object... values) {
- Validate.notNull(rowMapper, "rowMapper不能为空!");
- List<Object[]> result = createSQLQuery(sql, values).list();
- return buildListResultFromRowMapper(rowMapper, result);
- }
- /**
- * 按SQL查询对象列表,并将结果集转换成指定的对象列表
- *
- * @param values 数量可变的参数,按顺序绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> List<X> findBySQL(final String sql, final Object... values) {
- return createSQLQuery(sql, values).list();
- }
- /**
- * 按HQL查询对象列表.
- *
- * @param values 命名参数,按名称绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> List<X> findByHQL(final String hql, final Map<String, ?> values) {
- return createHQLQuery(hql, values).list();
- }
- /**
- * 按HQL查询对象列表,并将结果集封装成对象列表
- *
- * @param values 命名参数,按名称绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> List<X> findByHQLRowMapper(RowMapper<X> rowMapper,final String hql, final Map<String, ?> values) {
- Validate.notNull(rowMapper, "rowMapper不能为空!");
- List<Object[]> result = createHQLQuery(hql, values).list();
- return buildListResultFromRowMapper(rowMapper, result);
- }
- /**
- * 按SQL查询对象列表.
- * @param sql SQL查询语句
- * @param values 命名参数,按名称绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> List<X> findBySQL(final String sql, final Map<String, ?> values) {
- return createSQLQuery(sql, values).list();
- }
- /**
- * 查询在xxx.hbm.xml中配置的查询语句
- * @param queryName 查询的名称
- * @param parameters 参数
- * @return
- */
- public <X> List<X> findByNamedQuery(final String queryName, final Map<String, ?> parameters) {
- StatementTemplate statementTemplate = templateCache.get(queryName);
- String statement = processTemplate(statementTemplate,parameters);
- if(statementTemplate.getType() == StatementTemplate.TYPE.HQL){
- return this.findByHQL(statement);
- }else{
- return this.findBySQL(statement);
- }
- }
- /**
- * 查询在xxx.hbm.xml中配置的查询语句
- * @param rowMapper
- * @param queryName 查询的名称
- * @param parameters 参数
- * @return
- */
- public <X> List<X> findByNamedQuery(RowMapper<X> rowMapper,final String queryName, final Map<String, ?> parameters) {
- StatementTemplate statementTemplate = templateCache.get(queryName);
- String statement = processTemplate(statementTemplate,parameters);
- if(statementTemplate.getType() == StatementTemplate.TYPE.HQL){
- return this.findByHQLRowMapper(rowMapper,statement);
- }else{
- return this.findBySQLRowMapper(rowMapper,statement);
- }
- }
- /**
- * 按SQL查询对象列表,并将结果集封装成对象列表
- * @param sql SQL查询语句
- * @param values 命名参数,按名称绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> List<X> findBySQLRowMapper(RowMapper<X> rowMapper,final String sql, final Map<String, ?> values) {
- Validate.notNull(rowMapper, "rowMapper不能为空!");
- List<Object[]> result = createSQLQuery(sql, values).list();
- return buildListResultFromRowMapper(rowMapper, result);
- }
- /**
- * 按HQL查询唯一对象.
- *
- * @param values 数量可变的参数,按顺序绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> X findUniqueByHQL(final String hql, final Object... values) {
- return (X) createHQLQuery(hql, values).uniqueResult();
- }
- /**
- * 按SQL查询唯一对象.
- *
- * @param values 数量可变的参数,按顺序绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> X findUniqueBySQL(final String sql, final Object... values) {
- return (X) createSQLQuery(sql, values).uniqueResult();
- }
- /**
- * 按HQL查询唯一对象.
- *
- * @param values 命名参数,按名称绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> X findUniqueByHQL(final String hql, final Map<String, ?> values) {
- return (X) createHQLQuery(hql, values).uniqueResult();
- }
- /**
- * 按HQL查询唯一对象.
- * @param sql sql语句
- * @param values 命名参数,按名称绑定.
- */
- @SuppressWarnings("unchecked")
- public <X> X findUniqueBySQL(final String sql, final Map<String, ?> values) {
- return (X) createSQLQuery(sql, values).uniqueResult();
- }
- /**
- * 执行HQL进行批量修改/删除操作.
- *
- * @param values 数量可变的参数,按顺序绑定.
- * @return 更新记录数.
- */
- public int batchExecuteHQL(final String hql, final Object... values) {
- return createHQLQuery(hql, values).executeUpdate();
- }
- /**
- * 执行SQL进行批量修改/删除操作.
- *
- * @param sql sql语句
- * @param values 数量可变的参数,按顺序绑定.
- * @return 更新记录数.
- */
- public int batchExecuteSQL(final String sql, final Object... values) {
- return createSQLQuery(sql, values).executeUpdate();
- }
- /**
- * 执行HQL进行批量修改/删除操作.
- *
- * @param values 命名参数,按名称绑定.
- * @return 更新记录数.
- */
- public int batchExecuteHQL(final String hql, final Map<String, ?> values) {
- return createHQLQuery(hql, values).executeUpdate();
- }
- /**
- * 执行SQL进行批量修改/删除操作.
- *
- * @param values 命名参数,按名称绑定.
- * @return 更新记录数.
- */
- public int batchExecuteSQL(final String sql, final Map<String, ?> values) {
- return createSQLQuery(sql, values).executeUpdate();
- }
- /**
- * 根据查询HQL与参数列表创建Query对象.
- * 与find()函数可进行更加灵活的操作.
- *
- * @param values 数量可变的参数,按顺序绑定.
- */
- public Query createHQLQuery(final String queryString, final Object... values) {
- Query query = getSession().createQuery(queryString);
- if (values != null) {
- for (int i = 0; i < values.length; i++) {
- query.setParameter(i, values[i]);
- }
- }
- return query;
- }
- /**
- * 根据查询SQL与参数列表创建Query对象.
- * 与find()函数可进行更加灵活的操作.
- * @param sqlQueryString sql语句
- *
- * @param values 数量可变的参数,按顺序绑定.
- */
- public Query createSQLQuery(final String sqlQueryString, final Object... values) {
- Query query = getSession().createSQLQuery(sqlQueryString);
- if (values != null) {
- for (int i = 0; i < values.length; i++) {
- query.setParameter(i, values[i]);
- }
- }
- return query;
- }
- /**
- * 根据查询HQL与参数列表创建Query对象.
- * 与find()函数可进行更加灵活的操作.
- *
- * @param values 命名参数,按名称绑定.
- */
- public Query createHQLQuery(final String queryString, final Map<String, ?> values) {
- Query query = getSession().createQuery(queryString);
- if (values != null) {
- query.setProperties(values);
- }
- return query;
- }
- /**
- * 根据查询SQL与参数列表创建Query对象.
- * 与find()函数可进行更加灵活的操作.
- * @param queryString SQL语句
- * @param values 命名参数,按名称绑定.
- */
- public Query createSQLQuery(final String queryString, final Map<String, ?> values) {
- Query query = getSession().createSQLQuery(queryString);
- if (values != null) {
- query.setProperties(values);
- }
- return query;
- }
- /**
- * 按Criteria查询对象列表.
- *
- * @param criterions 数量可变的Criterion.
- */
- @SuppressWarnings("unchecked")
- public List<T> find(final Criterion... criterions) {
- return createCriteria(criterions).list();
- }
- /**
- * 按Criteria查询唯一对象.
- *
- * @param criterions 数量可变的Criterion.
- */
- @SuppressWarnings("unchecked")
- public T findUnique(final Criterion... criterions) {
- return (T) createCriteria(criterions).uniqueResult();
- }
- /**
- * 根据Criterion条件创建Criteria.
- * 与find()函数可进行更加灵活的操作.
- *
- * @param criterions 数量可变的Criterion.
- */
- public Criteria createCriteria(final Criterion... criterions) {
- Criteria criteria = getSession().createCriteria(entityClass);
- for (Criterion c : criterions) {
- criteria.add(c);
- }
- return criteria;
- }
- /**
- * 初始化对象.
- * 使用load()方法得到的仅是对象Proxy, 在传到View层前需要进行初始化.
- * 如果传入entity, 则只初始化entity的直接属性,但不会初始化延迟加载的关联集合和属性.
- * 如需初始化关联属性,需执行:
- * Hibernate.initialize(user.getRoles()),初始化User的直接属性和关联集合.
- * Hibernate.initialize(user.getDescription()),初始化User的直接属性和延迟加载的Description属性.
- */
- public void initProxyObject(Object proxy) {
- Hibernate.initialize(proxy);
- }
- /**
- * Flush当前Session.
- */
- public void flush() {
- getSession().flush();
- }
- /**
- * 为Query添加distinct transformer.
- * 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理.
- */
- public Query distinct(Query query) {
- query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
- return query;
- }
- /**
- * 为Criteria添加distinct transformer.
- * 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理.
- */
- public Criteria distinct(Criteria criteria) {
- criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
- return criteria;
- }
- /**
- * 取得对象的主键名.
- */
- public String getIdName() {
- ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass);
- return meta.getIdentifierPropertyName();
- }
- /**
- * 判断对象的属性值在数据库内是否唯一.
- *
- * 在修改对象的情景下,如果属性新修改的值(value)等于属性原来的值(orgValue)则不作比较.
- */
- public boolean isPropertyUnique(final String propertyName, final Object newValue, final Object oldValue) {
- if (newValue == null || newValue.equals(oldValue)) {
- return true;
- }
- Object object = findUniqueBy(propertyName, newValue);
- return (object == null);
- }
- @Override
- public void update(T object) {
- getSession().update(object);
- }
- @SuppressWarnings("unchecked")
- @Override
- public T load(ID id) {
- return (T) getSession().load(this.entityClass, id);
- }
- /**
- * 将list转化为数组
- * @param list
- * @return
- */
- protected Criterion[] list2Array(List<Criterion> list){
- if(list == null){
- return new Criterion[0];
- }
- Criterion[] result = new Criterion[list.size()];
- for(int i = 0; i < list.size(); i++){
- result[i] = list.get(i);
- }
- return result;
- }
- @Override
- public void afterPropertiesSet() throws Exception {
- templateCache = new HashMap<String, StatementTemplate>();
- if(this.dynamicStatementBuilder == null){
- this.dynamicStatementBuilder = new NoneDynamicHibernateStatementBuilder();
- }
- dynamicStatementBuilder.init();
- Map<String,String> namedHQLQueries = dynamicStatementBuilder.getNamedHQLQueries();
- Map<String,String> namedSQLQueries = dynamicStatementBuilder.getNamedSQLQueries();
- Configuration configuration = new Configuration();
- configuration.setNumberFormat("#");
- StringTemplateLoader stringLoader = new StringTemplateLoader();
- for(Entry<String, String> entry : namedHQLQueries.entrySet()){
- stringLoader.putTemplate(entry.getKey(), entry.getValue());
- templateCache.put(entry.getKey(), new StatementTemplate(StatementTemplate.TYPE.HQL,new Template(entry.getKey(),new StringReader(entry.getValue()),configuration)));
- }
- for(Entry<String, String> entry : namedSQLQueries.entrySet()){
- stringLoader.putTemplate(entry.getKey(), entry.getValue());
- templateCache.put(entry.getKey(), new StatementTemplate(StatementTemplate.TYPE.SQL,new Template(entry.getKey(),new StringReader(entry.getValue()),configuration)));
- }
- configuration.setTemplateLoader(stringLoader);
- }
- protected String processTemplate(StatementTemplate statementTemplate,Map<String, ?> parameters){
- StringWriter stringWriter = new StringWriter();
- try {
- statementTemplate.getTemplate().process(parameters, stringWriter);
- } catch (Exception e) {
- LOGER.error("处理DAO查询参数模板时发生错误:{}",e.toString());
- throw new SysException(e);
- }
- return stringWriter.toString();
- }
- }
我们的SimpleHibernateDAO实现了InitializingBean,在其afterProperties方法中我们将调用DynamicHibernateStatementBuilder把语句缓存起来
上层方法调用示例-这个已经非常类似ibatis了
- public List<Resource> getDescendants(Long userId,String code) {
- Map<String, Object> values = new HashMap<String, Object>();
- values.put("userId", String.valueOf(userId));
- values.put("code", code);
- values.put("type", String.valueOf(ResourceTypeEnum.URL_RESOURCE.getType()));
- values.put("status", String.valueOf(ResourceStatusEnum.ACTIVE.getStatus()));
- return this.findByNamedQuery(new ResourceRowMapper(),"resource.getDescendants", values);
- }
相关推荐
Hibernate 通过 HQL(Hibernate Query Language)或 Criteria API 提供查询功能,这些工具能够生成相应的 SQL 语句,使得开发者无需直接编写 SQL 即可进行数据库操作。此外,Hibernate 还支持对象关系的复杂映射,如...
为了显示查询SQL,Hibernate 提供了`hibernatetool`,可以生成SQL脚本,或者通过配置`logging.level.org.hibernate.SQL`来打印SQL语句。此外,Hibernate的日志系统支持JDK Logging、Log4j 和 SLF4J。 **显示查询SQL...
3. **支持动态SQL**:ibatis支持根据条件动态构建SQL语句,这对于复杂的查询场景非常有用。 4. **易于调试**:由于SQL语句是独立于Java代码的,因此在出现问题时更容易定位问题所在。 5. **性能优势**:ibatis通常被...
它支持动态SQL,可以方便地进行条件查询和数据操作。 **Hibernate** 则是一个更全面的对象关系映射框架,它提供了一种自动化的对象持久化机制,将Java对象直接映射到数据库表,简化了数据库访问。Hibernate通过实体...
此外,Hibernate提供了强大的 Criteria API 和 HQL(Hibernate Query Language),使得查询更加灵活。 **配置和使用步骤:** 1. 编写Hibernate配置文件(通常为`hibernate.cfg.xml`),包含数据库连接信息、方言等...
Hibernate 3.2是一个稳定且功能丰富的版本,提供了包括HQL(Hibernate查询语言)在内的多种查询方式,增强了性能和缓存机制,支持JPA(Java Persistence API)标准,使得与其它Java EE技术的集成更加方便。...
它允许开发者用Java对象来表示数据库中的记录,通过HQL(Hibernate查询语言)或SQL进行数据操作,降低了数据库操作的复杂性。 4. **Ibatis**:与Hibernate相比,Ibatis更轻量级,它将SQL语句直接写在配置文件或Java...
1. **需要手动编写 SQL:**相比于 Hibernate 自动生成 SQL,iBatis 需要手动编写 SQL 语句,增加了开发工作量。 2. **不支持自动关联:**当需要处理一对多或多对一的关系时,iBatis 需要手动编写额外的代码来实现...
它可能会强调动态SQL的使用,这是iBatis的一大特色,允许在运行时根据条件动态生成SQL语句。 整合Spring、Hibernate和iBatis,通常是在Spring中配置Hibernate或iBatis作为数据访问层。Spring通过DataSource、...
Hibernate支持事务管理,缓存机制,以及复杂的查询语言HQL,使得开发者能更专注于业务逻辑,而非底层的数据库交互。 然后是iBatis,它介于传统JDBC和完整的ORM框架之间,提供了一种灵活的SQL映射方式。iBatis的核心...
- **Hibernate:** Hibernate采用的是HQL(Hibernate Query Language)或Criteria API来进行查询操作,它们会根据定义的规则自动生成对应的SQL语句。这种方式减少了开发者编写SQL的工作量,但有时自动生成的SQL可能...
此外,Ibatis支持动态SQL,可以根据条件动态构建SQL语句,这在处理复杂的查询时非常有用。 Hibernate则是一个功能强大的对象关系映射(ORM)框架,它提供了一种在Java应用中管理和持久化对象的方式。Hibernate自动...
3. **开发与维护**:在开发效率上,二者相差不大,但iBatis的SQL保存于独立文件中,便于集中管理和维护,相较于Hibernate可能在Java代码中混合SQL/HQL,iBatis在可维护性方面略胜一筹。 ### 结论:选择的智慧 选择...
与Hibernate不同,iBatis并不负责对象的管理,而是将SQL语句和Java代码分离,通过XML配置文件或注解定义SQL语句,然后在代码中调用Executor执行。iBatis的主要优点在于灵活的SQL控制和良好的性能。 在实际项目中,...
iBatis是一个简单但功能丰富的SQL映射框架,它比Hibernate更轻量级,允许开发者自由控制SQL的编写。`ibatis 开发指南.pdf`可能讲解了如何配置iBatis,创建映射文件,以及在Java代码中调用SQL语句。iBatis适用于那些...
Hibernate支持事务管理、缓存策略和查询语言HQL,大大提升了开发效率。 最后,`iBatis`(MyBatis的前身)是一个轻量级的持久层框架,它不像Hibernate那样提供全套的ORM解决方案,而是更注重SQL的自由度。iBatis允许...
3. 可维护性:由于SQL保存在单独的文件中,iBATIS的可维护性优于Hibernate,后者有时会在Java代码中保存SQL或HQL。 iBATIS的工作流程主要包括: 1. 接收对象参数,该参数用于设置更新语句的输入值或查询语句的WHERE...
iBatis的核心思想是将SQL语句与Java对象进行映射,而不是根据映射定义自动生成SQL语句。这种方式使得iBatis在处理复杂查询时更加灵活,特别是在需要精细控制SQL语句的情况下。 #### 二、iBatis与Hibernate的区别 #...
2. **动态SQL**:支持在SQL语句中动态拼接条件,满足复杂查询需求。 3. **轻量级**:相比Hibernate,iBatis体积小,启动速度快,更易于理解和维护。 4. **更好的数据库性能**:由于iBatis允许直接编写SQL,开发者...
`easyquery`可能是一个简单的查询构建工具,允许开发者通过图形化界面构建复杂的查询条件,这样可以降低编写和维护SQL语句的难度。 总之,JQuery的启发在于其简洁的API和高效的处理方式,我们可以将其应用到对...