您的位置:首页 > 数据库

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

2016-06-23 11:49 831 查看
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语句的样例

[html] view
plain copy

print?

<?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属性和传入查询参数来得到最终解析出来的语句

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

[java] view
plain copy

print?

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

[html] view
plain copy

print?

<!-- 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校验器

[java] view
plain copy

print?

/**

* 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文件

[html] view
plain copy

print?

<?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:具体的)

[java] view
plain copy

print?

/**

* 动态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语句加载到内存中

[java] view
plain copy

print?

/**

* @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());

}

}

配置一下

[html] view
plain copy

print?

<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层代码

[java] view
plain copy

print?

/**

* 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了

[java] view
plain copy

print?

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 sqlhql