首页 > 数据库 >Hibernate_根据条件动态组装sql/hql语句(仿ibatis动态查询语句功能)

Hibernate_根据条件动态组装sql/hql语句(仿ibatis动态查询语句功能)

时间:2023-06-08 22:35:25浏览次数:37  
标签:语句 Hibernate return String public values sql 动态 final


 

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语句的样例


 


1. <?xml version="1.0" encoding="utf-8"?>  
2. <!DOCTYPE dynamic-hibernate-statement PUBLIC "-//Haier/HOP Hibernate Dynamic Statement DTD 1.0//EN"  
3. "http://www.haier.com/dtd/dynamic-hibernate-statement-1.0.dtd">  
4. <dynamic-hibernate-statement>  
5. <!-- 查询某个资源下的直接子节点 -->  
6. <hql-query name="resource.getChildren">  
7. <![CDATA[
8.         from Resource where parent.id=${parentId} and parent.id != id
9.     ]]>   
10. </hql-query>  
11. <!-- 查询系统中所有的root资源 -->  
12. <hql-query name="resource.getRoots">  
13. <![CDATA[
14.         from Resource where parent.id = id order by orderIndex
15.     ]]>   
16. </hql-query>  
17. <!-- 获取某个用户可访问的某个资源下的所有子资源 -->  
18. <sql-query name="resource.getDescendants">  
19. <![CDATA[
20.         select distinct t.id,
21.                         t.name,
22.                         t.description,
23.                         t.url,
24.                         t.type,
25.                         t.status,
26.                         t.code,
27.                         t.configuration,
28.                         t.module_name,
29.                         t.gmt_create,
30.                         t.gmt_modified,
31.                         t.create_by,
32.                         t.last_modified_by,
33.                         t.order_index,
34.                         t.parent_id
35.           from resource_info t
36.          inner join role_resource rr
37.             on t.id = rr.resource_id
38.          inner join user_role ur
39.             on rr.role_id = ur.role_id
40.          where ur.user_id = ${userId}
41.          <#if type == '1'>
42.             and t.type=1
43.             <#else>
44.             and t.type=0
45.          </#if>
46.            and t.type =  ${type}
47.            and t.status =  ${status}
48.          start with t.code = '${code}'
49.         connect by nocycle prior t.id = t.parent_id
50.     ]]>   
51. </sql-query>  
52. </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属性和传入查询参数来得到最终解析出来的语句

我们期望的方法可能是这样的:



 


1. 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属性用来唯一标示该语句,如下


 

1. <!-- HOP Hibernate Dynamic Statement Mapping DTD.  
2.   
3. <!DOCTYPE dynamic-hibernate-statement PUBLIC   
4.     "-//Haier/HOP Hibernate Dynamic Statement DTD 1.0//EN"  
5. >  
6.   
7. 这个文件时用来定义动态参数语句,类似itabis  
8.   
9. -->  
10.   
11. <!--
12.     The document root.
13.  -->  
14.   
15. <!ELEMENT dynamic-hibernate-statement (  
16.     (hql-query|sql-query)*  
17. )>  
18. <!-- default: none -->  
19.   
20. <!-- The query element declares a named Hibernate query string -->  
21.   
22. <!ELEMENT hql-query (#PCDATA)>  
23. >  
24.   
25. <!-- The sql-query element declares a named SQL query string -->  
26.   
27. <!ELEMENT sql-query (#PCDATA)>  
28. >



然后将其保存为dynamic-hibernate-statement-1.0.dtd,放在classpath下

编写DTD校验器

 


1. /**
2.  * hibernate动态sql dtd解析器
3.  * @author WangXuzheng
4.  *
5.  */  
6. public class DynamicStatementDTDEntityResolver implements EntityResolver, Serializable{  
7. private static final long serialVersionUID = 8123799007554762965L;  
8. private static final Logger LOGGER = LoggerFactory.getLogger( DynamicStatementDTDEntityResolver.class );  
9. private static final String HOP_DYNAMIC_STATEMENT = "http://www.haier.com/dtd/";  
10.   
11. public InputSource resolveEntity(String publicId, String systemId) {  
12. null; // returning null triggers default behavior  
13. if ( systemId != null ) {  
14. "trying to resolve system-id [" + systemId + "]" );  
15. if ( systemId.startsWith( HOP_DYNAMIC_STATEMENT ) ) {  
16. "recognized hop dyanmic statement namespace; attempting to resolve on classpath under com/haier/openplatform/dao/hibernate/" );  
17.                 source = resolveOnClassPath( publicId, systemId, HOP_DYNAMIC_STATEMENT );  
18.             }  
19.         }  
20. return source;  
21.     }  
22.   
23. private InputSource resolveOnClassPath(String publicId, String systemId, String namespace) {  
24. null;  
25. "com/haier/openplatform/dao/hibernate/" + systemId.substring( namespace.length() );  
26.         InputStream dtdStream = resolveInHibernateNamespace( path );  
27. if ( dtdStream == null ) {  
28. "unable to locate [" + systemId + "] on classpath" );  
29. if ( systemId.substring( namespace.length() ).indexOf( "2.0" ) > -1 ) {  
30. "Don't use old DTDs, read the Hibernate 3.x Migration Guide!" );  
31.             }  
32.         }  
33. else {  
34. "located [" + systemId + "] in classpath" );  
35. new InputSource( dtdStream );  
36.             source.setPublicId( publicId );  
37.             source.setSystemId( systemId );  
38.         }  
39. return source;  
40.     }  
41.   
42. protected InputStream resolveInHibernateNamespace(String path) {  
43. return this.getClass().getClassLoader().getResourceAsStream( path );  
44.     }  
45.   
46. protected InputStream resolveInLocalNamespace(String path) {  
47. try {  
48. return ConfigHelper.getUserResourceAsStream( path );  
49.         }  
50. catch ( Throwable t ) {  
51. return null;  
52.         }  
53.     }  
54. }


 

3.2编写sql文件



 


    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <!DOCTYPE dynamic-hibernate-statement PUBLIC "-//Haier/HOP Hibernate Dynamic Statement DTD 1.0//EN"  
    3. "http://www.haier.com/dtd/dynamic-hibernate-statement-1.0.dtd">  
    4. <dynamic-hibernate-statement>  
    5. <!-- 查询某个资源下的直接子节点 -->  
    6. <hql-query name="resource.getChildren">  
    7. <![CDATA[
    8.         from Resource where parent.id=${parentId} and parent.id != id
    9.     ]]>   
    10. </hql-query>  
    11. <!-- 查询系统中所有的root资源 -->  
    12. <hql-query name="resource.getRoots">  
    13. <![CDATA[
    14.         from Resource where parent.id = id order by orderIndex
    15.     ]]>   
    16. </hql-query>  
    17. <!-- 获取某个用户可访问的某个资源下的所有子资源 -->  
    18. <sql-query name="resource.getDescendants">  
    19. <![CDATA[
    20.         select distinct t.id,
    21.                         t.name,
    22.                         t.description,
    23.                         t.url,
    24.                         t.type,
    25.                         t.status,
    26.                         t.code,
    27.                         t.configuration,
    28.                         t.module_name,
    29.                         t.gmt_create,
    30.                         t.gmt_modified,
    31.                         t.create_by,
    32.                         t.last_modified_by,
    33.                         t.order_index,
    34.                         t.parent_id
    35.           from resource_info t
    36.          inner join role_resource rr
    37.             on t.id = rr.resource_id
    38.          inner join user_role ur
    39.             on rr.role_id = ur.role_id
    40.          where ur.user_id = ${userId}
    41.          <#if type == '1'>
    42.             and t.type=1
    43.             <#else>
    44.             and t.type=0
    45.          </#if>
    46.            and t.type =  ${type}
    47.            and t.status =  ${status}
    48.          start with t.code = '${code}'
    49.         connect by nocycle prior t.id = t.parent_id
    50.     ]]>   
    51. </sql-query>  
    52. </dynamic-hibernate-statement>



    3.3加载动态sql文件

    这里我们将加载sql/hql语句的程序独立到一个单独的类中,以便独立扩展

    这里一共3个方法,分表标示获取系统中sql/hql语句的map(key:语句名称,value:具体的)



     


    1. /**
    2.  * 动态sql/hql语句组装器
    3.  * @author WangXuzheng
    4.  *
    5.  */  
    6. public interface DynamicHibernateStatementBuilder {  
    7. /**
    8.      * hql语句map
    9.      * @return
    10.      */  
    11. public Map<String,String> getNamedHQLQueries();  
    12. /**
    13.      * sql语句map
    14.      * @return
    15.      */  
    16. public Map<String,String> getNamedSQLQueries();  
    17. /**
    18.      * 初始化
    19.      * @throws IOException 
    20.      */  
    21. public void init() throws IOException;  
    22. }

    默认的加载器-将指定配置文件中的sql/hql语句加载到内存中




      1. /**
      2.  * @author WangXuzheng
      3.  *
      4.  */  
      5. public class DefaultDynamicHibernateStatementBuilder implements DynamicHibernateStatementBuilder, ResourceLoaderAware {  
      6. private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDynamicHibernateStatementBuilder.class);  
      7. private Map<String, String> namedHQLQueries;  
      8. private Map<String, String> namedSQLQueries;  
      9. private String[] fileNames = new String[0];  
      10. private ResourceLoader resourceLoader;  
      11. private EntityResolver entityResolver = new DynamicStatementDTDEntityResolver();  
      12. /**
      13.      * 查询语句名称缓存,不允许重复
      14.      */  
      15. private Set<String> nameCache = new HashSet<String>();  
      16.   
      17. public void setFileNames(String[] fileNames) {  
      18. this.fileNames = fileNames;  
      19.     }  
      20.   
      21. @Override  
      22. public Map<String, String> getNamedHQLQueries() {  
      23. return namedHQLQueries;  
      24.     }  
      25.   
      26. @Override  
      27. public Map<String, String> getNamedSQLQueries() {  
      28. return namedSQLQueries;  
      29.     }  
      30.   
      31. @Override  
      32. public void init() throws IOException {  
      33. new HashMap<String, String>();  
      34. new HashMap<String, String>();  
      35. boolean flag = this.resourceLoader instanceof ResourcePatternResolver;  
      36. for (String file : fileNames) {  
      37. if (flag) {  
      38. this.resourceLoader).getResources(file);  
      39.                 buildMap(resources);  
      40. else {  
      41.                 Resource resource = resourceLoader.getResource(file);  
      42.                 buildMap(resource);  
      43.             }  
      44.         }  
      45. //clear name cache  
      46.         nameCache.clear();  
      47.     }  
      48.   
      49. @Override  
      50. public void setResourceLoader(ResourceLoader resourceLoader) {  
      51. this.resourceLoader = resourceLoader;  
      52.     }  
      53.   
      54. private void buildMap(Resource[] resources) throws IOException {  
      55. if (resources == null) {  
      56. return;  
      57.         }  
      58. for (Resource resource : resources) {  
      59.             buildMap(resource);  
      60.         }  
      61.     }  
      62.   
      63. @SuppressWarnings({ "rawtypes" })  
      64. private void buildMap(Resource resource) {  
      65. null;  
      66. try {  
      67. new InputSource(resource.getInputStream());  
      68.             XmlDocument metadataXml = MappingReader.INSTANCE.readMappingDocument(entityResolver, inputSource,  
      69. new OriginImpl("file", resource.getFilename()));  
      70. if (isDynamicStatementXml(metadataXml)) {  
      71. final Document doc = metadataXml.getDocumentTree();  
      72. final Element dynamicHibernateStatement = doc.getRootElement();  
      73.                 Iterator rootChildren = dynamicHibernateStatement.elementIterator();  
      74. while (rootChildren.hasNext()) {  
      75. final Element element = (Element) rootChildren.next();  
      76. final String elementName = element.getName();  
      77. if ("sql-query".equals(elementName)) {  
      78.                         putStatementToCacheMap(resource, element, namedSQLQueries);  
      79. else if ("hql-query".equals(elementName)) {  
      80.                         putStatementToCacheMap(resource, element, namedHQLQueries);  
      81.                     }  
      82.                 }  
      83.             }  
      84. catch (Exception e) {  
      85.             LOGGER.error(e.toString());  
      86. throw new SysException(e);  
      87. finally {  
      88. if (inputSource != null && inputSource.getByteStream() != null) {  
      89. try {  
      90.                     inputSource.getByteStream().close();  
      91. catch (IOException e) {  
      92.                     LOGGER.error(e.toString());  
      93. throw new SysException(e);  
      94.                 }  
      95.             }  
      96.         }  
      97.   
      98.     }  
      99.   
      100. private void putStatementToCacheMap(Resource resource, final Element element, Map<String, String> statementMap)  
      101. throws IOException {  
      102. "name").getText();  
      103.         Validate.notEmpty(sqlQueryName);  
      104. if (nameCache.contains(sqlQueryName)) {  
      105. throw new SysException("重复的sql-query/hql-query语句定义在文件:" + resource.getURI() + "中,必须保证name的唯一.");  
      106.         }  
      107.         nameCache.add(sqlQueryName);  
      108.         String queryText = element.getText();  
      109.         statementMap.put(sqlQueryName, queryText);  
      110.     }  
      111.   
      112. private static boolean isDynamicStatementXml(XmlDocument xmlDocument) {  
      113. return "dynamic-hibernate-statement".equals(xmlDocument.getDocumentTree().getRootElement().getName());  
      114.     }  
      115. }



      配置一下



       


      1.     <bean id="dynamicStatementBuilder" class="com.haier.openplatform.dao.hibernate.support.DefaultDynamicHibernateStatementBuilder">  
      2. <property name="fileNames">  
      3. <list>  
      4. <value>classpath*:/**/*-dynamic.xml</value><!--这里我们指定要加载某个文件夹下所有以-dynamic.xml结尾的文件 -->  
      5. </list>  
      6. </property>  
      7. </bean>  
      8. <bean id="baseHibernateDAO" class="com.haier.openplatform.dao.hibernate.BaseDAOHibernateImpl" abstract="true">  
      9. <property name="sessionFactory">  
      10. <ref bean="sessionFactory"/>  
      11. </property>  
      12. <property name="dynamicStatementBuilder" ref="dynamicStatementBuilder"/>  
      13. </bean>


      dao层代码



       



        1. /**
        2.  * Hibernate实现的DAO层
        3.  * @param <T> DAO操作的对象类型
        4.  * @param <ID> 主键类型
        5.  * @author WangXuzheng
        6.  *
        7.  */  
        8. public class SimpleHibernateDAO<T,ID extends Serializable> implements BaseDAO<T, ID>,InitializingBean{  
        9. private static final Logger LOGER = LoggerFactory.getLogger(SimpleHibernateDAO.class);  
        10. protected SessionFactory sessionFactory;  
        11. protected Class<T> entityClass;  
        12. /**
        13.      * 模板缓存
        14.      */  
        15. protected Map<String, StatementTemplate> templateCache;  
        16. protected DynamicHibernateStatementBuilder dynamicStatementBuilder;  
        17. /**
        18.      * 通过子类的泛型定义取得对象类型Class.
        19.      * eg.
        20.      * public class UserDao extends SimpleHibernateDao<User, Long>
        21.      */  
        22. public SimpleHibernateDAO() {  
        23. this.entityClass = Reflections.getSuperClassGenricType(getClass());  
        24.     }  
        25.   
        26. /**
        27.      * 取得sessionFactory.
        28.      */  
        29. public SessionFactory getSessionFactory() {  
        30. return sessionFactory;  
        31.     }  
        32.   
        33. /**
        34.      * 采用@Autowired按类型注入SessionFactory, 当有多个SesionFactory的时候在子类重载本函数.
        35.      */  
        36. public void setSessionFactory(final SessionFactory sessionFactory) {  
        37. this.sessionFactory = sessionFactory;  
        38.     }  
        39.   
        40. public void setDynamicStatementBuilder(DynamicHibernateStatementBuilder dynamicStatementBuilder) {  
        41. this.dynamicStatementBuilder = dynamicStatementBuilder;  
        42.     }  
        43.   
        44. /**
        45.      * 取得当前Session.
        46.      */  
        47. public Session getSession() {  
        48. return sessionFactory.getCurrentSession();  
        49.     }  
        50.   
        51. /**
        52.      * 保存新增或修改的对象.
        53.      */  
        54. @Override  
        55. public void save(final T entity) {  
        56. "entity不能为空");  
        57.         getSession().save(entity);  
        58. "save entity: {}", entity);  
        59.     }  
        60.   
        61. /**
        62.      * 删除对象.
        63.      * 
        64.      * @param entity 对象必须是session中的对象或含id属性的transient对象.
        65.      */  
        66. @Override  
        67. public void delete(final T entity) {  
        68. if(entity == null){  
        69. return;  
        70.         }  
        71.         getSession().delete(entity);  
        72. "delete entity: {}", entity);  
        73.     }  
        74.   
        75. /**
        76.      * 按id删除对象.
        77.      */  
        78. @Override  
        79. public void delete(final ID id) {  
        80. "id不能为空");  
        81.         delete(get(id));  
        82. "delete entity {},id is {}", entityClass.getSimpleName(), id);  
        83.     }  
        84.   
        85. /**
        86.      * 按id获取对象.
        87.      */  
        88. @SuppressWarnings("unchecked")  
        89. @Override  
        90. public T get(final ID id) {  
        91. "id不能为空");  
        92. return (T) getSession().get(entityClass, id);  
        93.     }  
        94.   
        95. /**
        96.      * 按id列表获取对象列表.
        97.      */  
        98. public List<T> get(final Collection<ID> ids) {  
        99. return find(Restrictions.in(getIdName(), ids));  
        100.     }  
        101.   
        102. /**
        103.      *  获取全部对象.
        104.      */  
        105. @Override  
        106. public List<T> getAll() {  
        107. return find();  
        108.     }  
        109.   
        110. /**
        111.      *  获取全部对象, 支持按属性行序.
        112.      */  
        113. @SuppressWarnings("unchecked")  
        114. public List<T> getAll(String orderByProperty, boolean isAsc) {  
        115.         Criteria c = createCriteria();  
        116. if (isAsc) {  
        117.             c.addOrder(Order.asc(orderByProperty));  
        118. else {  
        119.             c.addOrder(Order.desc(orderByProperty));  
        120.         }  
        121. return c.list();  
        122.     }  
        123.   
        124. /**
        125.      * 按属性查找对象列表, 匹配方式为相等.
        126.      */  
        127. public List<T> findBy(final String propertyName, final Object value) {  
        128.         Criterion criterion = Restrictions.eq(propertyName, value);  
        129. return find(criterion);  
        130.     }  
        131.   
        132. /**
        133.      * 按属性查找唯一对象, 匹配方式为相等.
        134.      */  
        135. @SuppressWarnings("unchecked")  
        136. @Override  
        137. public T findUniqueBy(final String propertyName, final Object value) {  
        138.         Criterion criterion = Restrictions.eq(propertyName, value);  
        139. return ((T) createCriteria(criterion).uniqueResult());  
        140.     }  
        141.   
        142. /**
        143.      * 按HQL查询对象列表.
        144.      * 
        145.      * @param values 数量可变的参数,按顺序绑定.
        146.      */  
        147. @SuppressWarnings("unchecked")  
        148. public <X> List<X> findByHQL(final String hql, final Object... values) {  
        149. return createHQLQuery(hql, values).list();  
        150.     }  
        151.       
        152. /**
        153.      * 按HQL查询对象列表,并将对象封装成指定的对象
        154.      * 
        155.      * @param values 数量可变的参数,按顺序绑定.
        156.      */  
        157. @SuppressWarnings("unchecked")  
        158. public <X> List<X> findByHQLRowMapper(RowMapper<X> rowMapper,final String hql, final Object... values) {  
        159. "rowMapper不能为空!");  
        160.         List<Object[]> result = createHQLQuery(hql, values).list();  
        161. return buildListResultFromRowMapper(rowMapper, result);  
        162.     }  
        163.   
        164. protected <X> List<X> buildListResultFromRowMapper(RowMapper<X> rowMapper, List<Object[]> result) {  
        165. new ArrayList<X>(result.size());  
        166. for(Object[] obj : result){  
        167.             rs.add(rowMapper.fromColumn(obj));  
        168.         }  
        169. return rs;  
        170.     }  
        171.       
        172.       
        173. /**
        174.      * 按SQL查询对象列表.
        175.      * 
        176.      * @param values 数量可变的参数,按顺序绑定.
        177.      */  
        178. @SuppressWarnings("unchecked")  
        179. public <X> List<X> findBySQLRowMapper(RowMapper<X> rowMapper,final String sql, final Object... values) {  
        180. "rowMapper不能为空!");  
        181.         List<Object[]> result = createSQLQuery(sql, values).list();  
        182. return buildListResultFromRowMapper(rowMapper, result);  
        183.     }  
        184.       
        185. /**
        186.      * 按SQL查询对象列表,并将结果集转换成指定的对象列表
        187.      * 
        188.      * @param values 数量可变的参数,按顺序绑定.
        189.      */  
        190. @SuppressWarnings("unchecked")  
        191. public <X> List<X> findBySQL(final String sql, final Object... values) {  
        192. return createSQLQuery(sql, values).list();  
        193.     }  
        194.   
        195. /**
        196.      * 按HQL查询对象列表.
        197.      * 
        198.      * @param values 命名参数,按名称绑定.
        199.      */  
        200. @SuppressWarnings("unchecked")  
        201. public <X> List<X> findByHQL(final String hql, final Map<String, ?> values) {  
        202. return createHQLQuery(hql, values).list();  
        203.     }  
        204.       
        205. /**
        206.      * 按HQL查询对象列表,并将结果集封装成对象列表
        207.      * 
        208.      * @param values 命名参数,按名称绑定.
        209.      */  
        210. @SuppressWarnings("unchecked")  
        211. public <X> List<X> findByHQLRowMapper(RowMapper<X> rowMapper,final String hql, final Map<String, ?> values) {  
        212. "rowMapper不能为空!");  
        213.         List<Object[]> result = createHQLQuery(hql, values).list();  
        214. return buildListResultFromRowMapper(rowMapper, result);  
        215.     }  
        216.       
        217. /**
        218.      * 按SQL查询对象列表.
        219.      * @param sql SQL查询语句
        220.      * @param values 命名参数,按名称绑定.
        221.      */  
        222. @SuppressWarnings("unchecked")  
        223. public <X> List<X> findBySQL(final String sql, final Map<String, ?> values) {  
        224. return createSQLQuery(sql, values).list();  
        225.     }  
        226.       
        227. /**
        228.      * 查询在xxx.hbm.xml中配置的查询语句
        229.      * @param queryName 查询的名称
        230.      * @param parameters 参数
        231.      * @return
        232.      */  
        233. public <X> List<X> findByNamedQuery(final String queryName, final Map<String, ?> parameters) {  
        234.         StatementTemplate statementTemplate = templateCache.get(queryName);  
        235.         String statement = processTemplate(statementTemplate,parameters);  
        236. if(statementTemplate.getType() == StatementTemplate.TYPE.HQL){  
        237. return this.findByHQL(statement);  
        238. else{  
        239. return this.findBySQL(statement);  
        240.         }  
        241.     }  
        242.       
        243. /**
        244.      * 查询在xxx.hbm.xml中配置的查询语句
        245.      * @param rowMapper
        246.      * @param queryName 查询的名称
        247.      * @param parameters 参数
        248.      * @return
        249.      */  
        250. public <X> List<X> findByNamedQuery(RowMapper<X> rowMapper,final String queryName, final Map<String, ?> parameters) {  
        251.         StatementTemplate statementTemplate = templateCache.get(queryName);  
        252.         String statement = processTemplate(statementTemplate,parameters);  
        253. if(statementTemplate.getType() == StatementTemplate.TYPE.HQL){  
        254. return this.findByHQLRowMapper(rowMapper,statement);  
        255. else{  
        256. return this.findBySQLRowMapper(rowMapper,statement);  
        257.         }  
        258.     }  
        259.       
        260. /**
        261.      * 按SQL查询对象列表,并将结果集封装成对象列表
        262.      * @param sql SQL查询语句
        263.      * @param values 命名参数,按名称绑定.
        264.      */  
        265. @SuppressWarnings("unchecked")  
        266. public <X> List<X> findBySQLRowMapper(RowMapper<X> rowMapper,final String sql, final Map<String, ?> values) {  
        267. "rowMapper不能为空!");  
        268.         List<Object[]> result = createSQLQuery(sql, values).list();  
        269. return buildListResultFromRowMapper(rowMapper, result);  
        270.     }  
        271.   
        272. /**
        273.      * 按HQL查询唯一对象.
        274.      * 
        275.      * @param values 数量可变的参数,按顺序绑定.
        276.      */  
        277. @SuppressWarnings("unchecked")  
        278. public <X> X findUniqueByHQL(final String hql, final Object... values) {  
        279. return (X) createHQLQuery(hql, values).uniqueResult();  
        280.     }  
        281.       
        282. /**
        283.      * 按SQL查询唯一对象.
        284.      * 
        285.      * @param values 数量可变的参数,按顺序绑定.
        286.      */  
        287. @SuppressWarnings("unchecked")  
        288. public <X> X findUniqueBySQL(final String sql, final Object... values) {  
        289. return (X) createSQLQuery(sql, values).uniqueResult();  
        290.     }  
        291.   
        292. /**
        293.      * 按HQL查询唯一对象.
        294.      * 
        295.      * @param values 命名参数,按名称绑定.
        296.      */  
        297. @SuppressWarnings("unchecked")  
        298. public <X> X findUniqueByHQL(final String hql, final Map<String, ?> values) {  
        299. return (X) createHQLQuery(hql, values).uniqueResult();  
        300.     }  
        301.       
        302. /**
        303.      * 按HQL查询唯一对象.
        304.      * @param sql sql语句
        305.      * @param values 命名参数,按名称绑定.
        306.      */  
        307. @SuppressWarnings("unchecked")  
        308. public <X> X findUniqueBySQL(final String sql, final Map<String, ?> values) {  
        309. return (X) createSQLQuery(sql, values).uniqueResult();  
        310.     }  
        311.   
        312. /**
        313.      * 执行HQL进行批量修改/删除操作.
        314.      * 
        315.      * @param values 数量可变的参数,按顺序绑定.
        316.      * @return 更新记录数.
        317.      */  
        318. public int batchExecuteHQL(final String hql, final Object... values) {  
        319. return createHQLQuery(hql, values).executeUpdate();  
        320.     }  
        321.       
        322. /**
        323.      * 执行SQL进行批量修改/删除操作.
        324.      * 
        325.      * @param sql sql语句
        326.      * @param values 数量可变的参数,按顺序绑定.
        327.      * @return 更新记录数.
        328.      */  
        329. public int batchExecuteSQL(final String sql, final Object... values) {  
        330. return createSQLQuery(sql, values).executeUpdate();  
        331.     }  
        332.   
        333. /**
        334.      * 执行HQL进行批量修改/删除操作.
        335.      * 
        336.      * @param values 命名参数,按名称绑定.
        337.      * @return 更新记录数.
        338.      */  
        339. public int batchExecuteHQL(final String hql, final Map<String, ?> values) {  
        340. return createHQLQuery(hql, values).executeUpdate();  
        341.     }  
        342.       
        343. /**
        344.      * 执行SQL进行批量修改/删除操作.
        345.      * 
        346.      * @param values 命名参数,按名称绑定.
        347.      * @return 更新记录数.
        348.      */  
        349. public int batchExecuteSQL(final String sql, final Map<String, ?> values) {  
        350. return createSQLQuery(sql, values).executeUpdate();  
        351.     }  
        352.   
        353. /**
        354.      * 根据查询HQL与参数列表创建Query对象.
        355.      * 与find()函数可进行更加灵活的操作.
        356.      * 
        357.      * @param values 数量可变的参数,按顺序绑定.
        358.      */  
        359. public Query createHQLQuery(final String queryString, final Object... values) {  
        360.         Query query = getSession().createQuery(queryString);  
        361. if (values != null) {  
        362. for (int i = 0; i < values.length; i++) {  
        363.                 query.setParameter(i, values[i]);  
        364.             }  
        365.         }  
        366. return query;  
        367.     }  
        368.       
        369. /**
        370.      * 根据查询SQL与参数列表创建Query对象.
        371.      * 与find()函数可进行更加灵活的操作.
        372.      * @param sqlQueryString sql语句
        373.      * 
        374.      * @param values 数量可变的参数,按顺序绑定.
        375.      */  
        376. public Query createSQLQuery(final String sqlQueryString, final Object... values) {  
        377.         Query query = getSession().createSQLQuery(sqlQueryString);  
        378. if (values != null) {  
        379. for (int i = 0; i < values.length; i++) {  
        380.                 query.setParameter(i, values[i]);  
        381.             }  
        382.         }  
        383. return query;  
        384.     }  
        385.   
        386. /**
        387.      * 根据查询HQL与参数列表创建Query对象.
        388.      * 与find()函数可进行更加灵活的操作.
        389.      * 
        390.      * @param values 命名参数,按名称绑定.
        391.      */  
        392. public Query createHQLQuery(final String queryString, final Map<String, ?> values) {  
        393.         Query query = getSession().createQuery(queryString);  
        394. if (values != null) {  
        395.             query.setProperties(values);  
        396.         }  
        397. return query;  
        398.     }  
        399.       
        400. /**
        401.      * 根据查询SQL与参数列表创建Query对象.
        402.      * 与find()函数可进行更加灵活的操作.
        403.      * @param queryString SQL语句
        404.      * @param values 命名参数,按名称绑定.
        405.      */  
        406. public Query createSQLQuery(final String queryString, final Map<String, ?> values) {  
        407.         Query query = getSession().createSQLQuery(queryString);  
        408. if (values != null) {  
        409.             query.setProperties(values);  
        410.         }  
        411. return query;  
        412.     }  
        413.   
        414. /**
        415.      * 按Criteria查询对象列表.
        416.      * 
        417.      * @param criterions 数量可变的Criterion.
        418.      */  
        419. @SuppressWarnings("unchecked")  
        420. public List<T> find(final Criterion... criterions) {  
        421. return createCriteria(criterions).list();  
        422.     }  
        423.   
        424. /**
        425.      * 按Criteria查询唯一对象.
        426.      * 
        427.      * @param criterions 数量可变的Criterion.
        428.      */  
        429. @SuppressWarnings("unchecked")  
        430. public T findUnique(final Criterion... criterions) {  
        431. return (T) createCriteria(criterions).uniqueResult();  
        432.     }  
        433.   
        434. /**
        435.      * 根据Criterion条件创建Criteria.
        436.      * 与find()函数可进行更加灵活的操作.
        437.      * 
        438.      * @param criterions 数量可变的Criterion.
        439.      */  
        440. public Criteria createCriteria(final Criterion... criterions) {  
        441.         Criteria criteria = getSession().createCriteria(entityClass);  
        442. for (Criterion c : criterions) {  
        443.             criteria.add(c);  
        444.         }  
        445. return criteria;  
        446.     }  
        447.   
        448. /**
        449.      * 初始化对象.
        450.      * 使用load()方法得到的仅是对象Proxy, 在传到View层前需要进行初始化.
        451.      * 如果传入entity, 则只初始化entity的直接属性,但不会初始化延迟加载的关联集合和属性.
        452.      * 如需初始化关联属性,需执行:
        453.      * Hibernate.initialize(user.getRoles()),初始化User的直接属性和关联集合.
        454.      * Hibernate.initialize(user.getDescription()),初始化User的直接属性和延迟加载的Description属性.
        455.      */  
        456. public void initProxyObject(Object proxy) {  
        457.         Hibernate.initialize(proxy);  
        458.     }  
        459.   
        460. /**
        461.      * Flush当前Session.
        462.      */  
        463. public void flush() {  
        464.         getSession().flush();  
        465.     }  
        466.   
        467. /**
        468.      * 为Query添加distinct transformer.
        469.      * 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理.
        470.      */  
        471. public Query distinct(Query query) {  
        472.         query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);  
        473. return query;  
        474.     }  
        475.   
        476. /**
        477.      * 为Criteria添加distinct transformer.
        478.      * 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理.
        479.      */  
        480. public Criteria distinct(Criteria criteria) {  
        481.         criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);  
        482. return criteria;  
        483.     }  
        484.   
        485. /**
        486.      * 取得对象的主键名.
        487.      */  
        488. public String getIdName() {  
        489.         ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass);  
        490. return meta.getIdentifierPropertyName();  
        491.     }  
        492.   
        493. /**
        494.      * 判断对象的属性值在数据库内是否唯一.
        495.      * 
        496.      * 在修改对象的情景下,如果属性新修改的值(value)等于属性原来的值(orgValue)则不作比较.
        497.      */  
        498. public boolean isPropertyUnique(final String propertyName, final Object newValue, final Object oldValue) {  
        499. if (newValue == null || newValue.equals(oldValue)) {  
        500. return true;  
        501.         }  
        502.         Object object = findUniqueBy(propertyName, newValue);  
        503. return (object == null);  
        504.     }  
        505.   
        506. @Override  
        507. public void update(T object) {  
        508.         getSession().update(object);  
        509.     }  
        510.   
        511. @SuppressWarnings("unchecked")  
        512. @Override  
        513. public T load(ID id) {  
        514. return (T) getSession().load(this.entityClass, id);  
        515.     }  
        516.       
        517. /**
        518.      * 将list转化为数组
        519.      * @param list
        520.      * @return
        521.      */  
        522. protected Criterion[] list2Array(List<Criterion> list){  
        523. if(list == null){  
        524. return new Criterion[0];  
        525.         }  
        526. new Criterion[list.size()];  
        527. for(int i = 0; i < list.size(); i++){  
        528.             result[i] = list.get(i);  
        529.         }  
        530. return result;  
        531.     }  
        532.   
        533. @Override  
        534. public void afterPropertiesSet() throws Exception {  
        535. new HashMap<String, StatementTemplate>();  
        536. if(this.dynamicStatementBuilder == null){  
        537. this.dynamicStatementBuilder = new NoneDynamicHibernateStatementBuilder();  
        538.         }  
        539.         dynamicStatementBuilder.init();  
        540.         Map<String,String> namedHQLQueries = dynamicStatementBuilder.getNamedHQLQueries();  
        541.         Map<String,String> namedSQLQueries = dynamicStatementBuilder.getNamedSQLQueries();  
        542. new Configuration();  
        543. "#");  
        544. new StringTemplateLoader();  
        545. for(Entry<String, String> entry : namedHQLQueries.entrySet()){  
        546.             stringLoader.putTemplate(entry.getKey(), entry.getValue());  
        547. new StatementTemplate(StatementTemplate.TYPE.HQL,new Template(entry.getKey(),new StringReader(entry.getValue()),configuration)));  
        548.         }  
        549. for(Entry<String, String> entry : namedSQLQueries.entrySet()){  
        550.             stringLoader.putTemplate(entry.getKey(), entry.getValue());  
        551. new StatementTemplate(StatementTemplate.TYPE.SQL,new Template(entry.getKey(),new StringReader(entry.getValue()),configuration)));  
        552.         }  
        553.         configuration.setTemplateLoader(stringLoader);  
        554.     }  
        555.       
        556. protected String processTemplate(StatementTemplate statementTemplate,Map<String, ?> parameters){  
        557. new StringWriter();  
        558. try {  
        559.             statementTemplate.getTemplate().process(parameters, stringWriter);  
        560. catch (Exception e) {  
        561. "处理DAO查询参数模板时发生错误:{}",e.toString());  
        562. throw new SysException(e);  
        563.         }  
        564. return stringWriter.toString();  
        565.     }  
        566. }



        我们的SimpleHibernateDAO实现了InitializingBean,在其afterProperties方法中我们将调用DynamicHibernateStatementBuilder把语句缓存起来
        上层方法调用示例-这个已经非常类似ibatis了


         


        1. public List<Resource> getDescendants(Long userId,String code) {  
        2. new HashMap<String, Object>();  
        3. "userId", String.valueOf(userId));  
        4. "code", code);  
        5. "type", String.valueOf(ResourceTypeEnum.URL_RESOURCE.getType()));  
        6. "status", String.valueOf(ResourceStatusEnum.ACTIVE.getStatus()));  
        7. return this.findByNamedQuery(new ResourceRowMapper(),"resource.getDescendants", values);  
        8. }

        标签:语句,Hibernate,return,String,public,values,sql,动态,final
        From: https://blog.51cto.com/u_16070335/6443837

        相关文章

        • 路由器动态路由的配置方法
          RIP:RoutingInformationProtocol,路由信息协议,是应用较早、使用较普遍的IGP内部网关协议,适用于小型同类网络,是典型的距离矢量协议。 RIP协议跳数作为衡量路径开销的,RIP协议里规定最大跳数为15。 RIP协议有两个版本RIPv1和RIPv2。 RIPv1属于有类路由协议,不支持VLSM(变长子......
        • 深入浅出模板模式和动态代理
          模板模式模板模式是使用最频繁的设计模式之一,如果能正确的使用好模板模式,能使代码更加优雅,同时也便于后期维护和扩展。另外也是面试常问的设计模式之一。本次Chat分享的是易懂版模板模式,首先了解模板模式,然后会例举多个生活实例,再写一个案例,最后介绍Spring和Mybatis源码......
        • 如何把Hibernate2.1升级到Hibernate3.0
          如何把Hibernate2.1升级到Hibernate3.0?选自<<精通Hibernate:Java对象持久化技术详解>>作者:孙卫琴1.1.1包名1.1.2org.hibernate.classic包1.1.3Hibernate所依赖的第三方软件包1.1.4异常模型1.1.5Session接口1.1.6createSQLQuery()1.1.7Lifecycle和Validatable接......
        • Hibernate多对多删除问题的解决
          Hibernate多对多删除问题的解决关键字:hibernate,多对多,删除Hibernate多对多的例子不少,但仔细一看,大多数都是保存的,删除谈的少,但问题还不少,因此有必须简单测试一下,以下我们来个简单的多对多关系建立老师Teacher与课程Course是一个多对多的关系,Pojo与XMl配置如下。 Pojo......
        • Javascript动态修改select选项
          1、向Select里添加OptionJs代码1.//IEonly,FF不支持Add方法2.functionfnAddItem(text,value){3.varselTarget=document.getElementById("selID");4.selTarget.Add(newOption("text","value"));5.}6.......
        • 如何在Spark中使用动态数据转置
          DynamicTranspose是Spark中的一个关键转换,因为它需要大量的迭代。本文将为您提供有关如何使用内存中运算符处理此复杂方案的清晰概念。首先,让我们看看我们拥有的源数据: idoc_number,订单ID,idoc_qualifier_org,idoc_org7738,2364,6,07738,2364,7,07738,2364,8,mystr17738,2364,12,myst......
        • mysql 查询语句
          一、mysql查询的五种子句    where(条件查询)、having(筛选)、groupby(分组)、orderby(排序)、limit(限制结果数)   1、where常用运算符:      比较运算符        >, < , = , !=(<>), >= , <=         i......
        • vue之动态组件&插槽
          1.动态组件<!--<component:is="who"></component>--><!--component标签的is属性等于组件名字,这里就会显示这个组件--><!--keep-alive的使用:可以将组件缓存,后期切过来时资源不会被销毁--><!--动态组件start--><divid="trends"><button@click=&......
        • Java面试题查缺补漏习题,锁的升级,动态代理
          之前我们总结了Java面试题目中的关于计算机网络,操作系统,以及JVM虚拟机,以及Java的相关特性。今天又看了很多面试的视频,对面试的题目进行一下仔细的补充。1.对称加密与非对称加密的区别:非对称加密和对称加密在加密和解密过程、加密解密速度、传输的安全性上都有所不同,具体介绍如下:......
        • sql语句基础
          sql语句基础  ----------------------------------------------------------sqlstructuredquerylanguage--DML--DataManipulationLanguage--数据操作语言queryinformation(SELECT),addnewrows(INSERT),modifyexistingrows(UPDATE),......