/** * Copyright (c) 2005-2009 springside.org.cn * * Licensed under the Apache License, Version 2.0 (the "License"); * * $Id: SimpleHibernateDao.java 1139 2010-07-31 15:25:32Z calvinxiu $ */ package com.lakeside.data.sqldb; import com.lakeside.core.utils.Assert; import com.lakeside.core.utils.ReflectionUtils; import org.hibernate.*; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Restrictions; import org.hibernate.metadata.ClassMetadata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.FatalBeanException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import javax.sql.DataSource; import java.beans.PropertyDescriptor; import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 封装Hibernate原生API的DAO泛型基类. * * 可在Service层直接使用,也可以扩展泛型DAO子类使用. * 参考Spring2.5自带的Petlinc例子,取消了HibernateTemplate,直接使用Hibernate原生API. * * @param <T> DAO操作的对象类型 * @param <PK> 主键类型 * * @author calvin */ @SuppressWarnings("unchecked") public class BaseDao<T, PK extends Serializable> { protected Logger logger = LoggerFactory.getLogger(getClass()); protected SessionFactory sessionFactory; protected Class<T> entityClass; protected NamedParameterJdbcTemplate jdbcTemplate; private DataSource dataSource; public static final HashMap<String,Object> EMPTY_PARAMETER = null; /** * 用于Dao层子类使用的构造函数. * 通过子类的泛型定义取得对象类型Class. * eg. * public class UserDao extends BaseDao<User, Long> */ public BaseDao() { this.entityClass = ReflectionUtils.getSuperClassGenricType(getClass()); } /** * 用于用于省略Dao层, 在Service层直接使用通用BaseDao的构造函数. * 在构造函数中定义对象类型Class. * eg. * BaseDao<User, Long> userDao = new BaseDao<User, Long>(sessionFactory, User.class); */ public BaseDao(final SessionFactory sessionFactory, final Class<T> entityClass) { this.sessionFactory = sessionFactory; this.entityClass = entityClass; } /** * 取得sessionFactory. */ public SessionFactory getSessionFactory() { return sessionFactory; } /** * 采用@Autowired按类型注入SessionFactory, 当有多个SesionFactory的时候Override本函数. */ @Autowired public void setDataSource(final DataSource dataSource) { this.dataSource = dataSource; } /** * 采用@Autowired按类型注入SessionFactory, 当有多个SesionFactory的时候Override本函数. */ @Autowired public void setSessionFactory(final SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } @Autowired public void setJdbcTemplate(NamedParameterJdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } /** * 取得当前Session. */ public Session getSession() { return sessionFactory.getCurrentSession(); } /** * 保存新增或修改的对象. */ public void save(final T entity) { Assert.notNull(entity, "entity不能为空"); getSession().saveOrUpdate(entity); logger.debug("save entity: {}", entity); } /** * 删除对象. * * @param entity 对象必须是session中的对象或含id属性的transient对象. */ public void delete(final T entity) { Assert.notNull(entity, "entity不能为空"); getSession().delete(entity); logger.debug("delete entity: {}", entity); } /** * 按id删除对象. */ public void delete(final PK id) { Assert.notNull(id, "id不能为空"); delete(get(id)); logger.debug("delete entity {},id is {}", entityClass.getSimpleName(), id); } /** * 初始化对象. * 使用load()方法得到的仅是对象Proxy, 在传到View层前需要进行初始化. * 只初始化entity的直接属性,但不会初始化延迟加载的关联集合和属性. * 如需初始化关联属性,可实现新的函数,执行: * Hibernate.initialize(user.getRoles()),初始化User的直接属性和关联集合. * Hibernate.initialize(user.getDescription()),初始化User的直接属性和延迟加载的Description属性. */ public void initProxyProperty(Object proxyProperty) { Hibernate.initialize(proxyProperty); } /** * Flush当前Session. */ public void flush() { getSession().flush(); } /** * 按id获取对象. */ public T get(final PK id) { Assert.notNull(id, "id不能为空"); return (T) getSession().get(entityClass, id); } /** * 获取全部对象. */ public List<T> getAll() { return find(); } /** * 合并对象 * @param entity * @return */ public T merge(final T entity){ Assert.notNull(entity, "entity不能为空"); Session session = getSession(); String idName = getIdName(); PropertyDescriptor idp= BeanUtils.getPropertyDescriptor(entityClass, idName); PK idvalue=null; try { idvalue = (PK)idp.getReadMethod().invoke(entity); } catch (Exception e) { throw new FatalBeanException("Could not copy properties from source to target", e); } T dest=null; if(idvalue!=null){ dest=(T)session.get(entityClass, idvalue); } if(dest!=null){ // merge the properties PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(entityClass); for (PropertyDescriptor p : descriptors) { if (p.getWriteMethod() != null) { try { Method readMethod = p.getReadMethod(); if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { readMethod.setAccessible(true); } Object value = readMethod.invoke(entity); if(value==null){ continue; } Method writeMethod = p.getWriteMethod(); if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(dest, value); } catch (Throwable ex) { throw new FatalBeanException("Could not copy properties from source to target", ex); } } } }else{ // destination object is empty, save the entity object parameted dest=entity; } session.saveOrUpdate(dest); logger.debug("merge entity: {}", entity); return dest; } /** * 按Criteria查询对象列表. * * @param criterions 数量可变的Criterion. */ public List<T> find(final Criterion... criterions) { return createCriteria(criterions).list(); } /** * 根据Criterion条件创建Criteria. * * 本类封装的find()函数全部默认返回对象类型为T,当不为T时使用本函数. * * @param criterions 数量可变的Criterion. */ protected Criteria createCriteria(final Criterion... criterions) { Criteria criteria = getSession().createCriteria(entityClass); for (Criterion c : criterions) { criteria.add(c); } return criteria; } /** * 按HQL查询对象列表. * * @param values 命名参数,按名称绑定. */ public <X> List<X> find(final String hql, final Map<String, ?> values) { return createQuery(hql, values).list(); } /** * 按HQL查询唯一对象. * 查询结果最多有一行,超过一行会抛出异常 * @param values 命名参数,按名称绑定. */ public <X> X findUnique(final String hql, final Map<String, ?> values) { return (X) createQuery(hql, values).uniqueResult(); } /** * 按属性查找唯一对象,匹配方式为相等. * 查询结果最多有一行,超过一行会抛出异常 */ public T findUniqueBy(final String propertyName, final Object value) { Assert.hasText(propertyName, "propertyName不能为空"); Criterion criterion = Restrictions.eq(propertyName, value); return (T) createCriteria(criterion).uniqueResult(); } /** * 执行HQL进行批量修改/删除操作. * @return 更新记录数. */ public int batchExecute(final String hql, final Map<String, ?> values) { Assert.hasText(hql, "hql不能为空"); return createQuery(hql, values).executeUpdate(); } /** * 根据查询HQL与参数列表创建Query对象. * * @param values 命名参数,按名称绑定. */ public Query createQuery(final String hql, final Map<String, ?> values) { Assert.hasText(hql, "hql不能为空"); Query query = getSession().createQuery(hql); if (values != null) { query.setProperties(values); } return query; } /** * 取得对象的主键名. */ public String getIdName() { ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass); return meta.getIdentifierPropertyName(); } /** * 基于jdbcTemplate查询count数或其他数字结果 * @param sql sql语句 * @param paramMap 命名参数,按名称绑定. * @return 结果列表必须为1行,否则抛出异常 */ public int jfindInt(final String sql, final Map<String, ?> paramMap) { return jdbcTemplate.queryForInt(sql, paramMap); } /** * 基于jdbcTemplate列表查询,并进行对象封装 * @param <X>转换为的对象 * @param paramMap 命名参数,按名称绑定. * @param elementType 要转换为的对象 * @return 查询结果列表,无对应结果时,返回空列表 */ public <X> List<X> jfind(final String sql, final Map<String, ?> paramMap, final Class<X> elementType) { return jdbcTemplate.query(sql, paramMap, new BeanPropertyRowMapper<X>(elementType)); } /** * 基于jdbcTemplate的列表查询 * @param paramMap 命名参数,按名称绑定. * @return 查询结果列表,无对应结果时,返回空列表 */ public List<Map<String, Object>> jfind(final String sql, final Map<String, ?> paramMap) { return jdbcTemplate.queryForList(sql, paramMap); } /** * 基于jdbcTemplate查询 * @param paramMap 命名参数,按名称绑定. * @return 返回第一个Map对象,没有时返回null */ public Map<String, Object> jfindUnique(final String sql, final Map<String, ?> paramMap) { List<Map<String, Object>> result = jfind(sql, paramMap); if (result == null || result.size() == 0) { return null; } return result.get(0); } /** * 基于jdbcTemplate查询,并进行对象封装 * @param paramMap 参数列表 * @param requiredType 封装的对象类型 * @return */ public <X> X jfindUnique(final String sql, final Map<String, ?> paramMap, Class<X> requiredType) { List<X> result = jfind(sql, paramMap, requiredType); if (result == null || result.size() == 0) { return null; } return result.get(0); } public long insertWithGeneratedKey(final String sql, final Map<String, ?> paramMap){ MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource(paramMap); KeyHolder keyHolder = new GeneratedKeyHolder(); int row = this.jdbcTemplate.update(sql, mapSqlParameterSource, keyHolder); if (row > 0) return keyHolder.getKey().longValue(); //line 72 return -1; } public Transaction begainTransaction(){ Session currentSession = this.sessionFactory.openSession(); Transaction tran = currentSession.beginTransaction(); tran.begin(); return tran; } protected Map<String, Object> newParameters(){ return new HashMap<String,Object>(); } }