Spring3整合Hibernate4-我们到底能走多远系列(30)
我们到底能走多远系列(30)
扯淡:
30篇啦!从2012-08-15开始的系列,东平西凑将近一年的时间也就这么几篇。目标的100篇,按这个速度也要再搞两年呢。
发博客果然不是件容易的事,怪不得更多的人愿意玩微博,125个字,写一个字也可以发了。
向那些依然坚持稳定码博客的朋友致敬!
主题:
用spring整合hibernate也算是java web开发的入门必学的东西了,多年下来没怎么用过hibernate。
所以记录下基础的整合知识,以及如何构建一些共通的代码,减少dao层的工作量。
项目使用maven构建,关于maven的构建知识可以参考:摸我
整合只使用了一个配置文件,hibernate方面使用注解方式映射数据库表。
data-source.xml:
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd " default-autowire="byName"> <context:component-scan base-package="com.sz.sh.dal.dao.hibernate,com.sz.sh.dal.dao.dateobject"> </context:component-scan> <!-- 使用常规的BasicDataSource 来配置DataSource--> <bean id="shDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="${sh.jdbc.url}" /> <property name="username" value="${sh.jdbc.username}" /> <property name="password" value="${sh.jdbc.password}" /> <property name="initialSize" value="1" /> <property name="maxIdle" value="30" /> <property name="maxWait" value="10000" /> <property name="minIdle" value="1" /> <property name="removeAbandoned" value="true" /> <property name="removeAbandonedTimeout" value="180" /> <!-- validate connection 检测配置 --> <property name="testWhileIdle" value="true" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <property name="validationQuery"> <value>SELECT @@SQL_MODE</value> </property> <property name="numTestsPerEvictionRun"> <value>30</value> </property> <property name="timeBetweenEvictionRunsMillis"> <value>60000</value> </property> <property name="minEvictableIdleTimeMillis"> <value>1800000</value> </property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="shDataSource" /> </bean> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager" /> </bean> <bean id="shSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="shDataSource" /> <property name="packagesToScan"> <list> <value>com.sz.sh.dal.dao.dateobject</value> </list> </property> <!-- 如果用xml来描述hibernate的bean,就需要以下的配置 <property name="mappingResources"> <list> <value>cn/sh/model/user.hbm.xml</value> </list> </property> --> <property name="hibernateProperties"> <props> <prop key="hibernate.default_schema">wxassistant</prop> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.query.substitutions">false</prop> <prop key="hibernate.default_batch_fetch_size">20</prop> <prop key="hibernate.max_fetch_depth">2</prop> <prop key="hibernate.generate_statistics">true</prop> </props> </property> </bean> <aop:aspectj-autoproxy expose-proxy="true" /><!-- 开启注解事务 只对当前配置文件有效 --> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="shSessionFactory" /> </bean> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="merge*" propagation="REQUIRED" /> <tx:method name="del*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="put*" propagation="REQUIRED" /> <tx:method name="use*" propagation="REQUIRED" /> <tx:method name="get*" propagation="REQUIRED" read-only="true" /> <tx:method name="count*" propagation="REQUIRED" read-only="true" /> <tx:method name="find*" propagation="REQUIRED" read-only="true" /> <tx:method name="list*" propagation="REQUIRED" read-only="true" /> <tx:method name="*" propagation="REQUIRED" read-only="true" /> </tx:attributes> </tx:advice> <aop:config expose-proxy="true"><!-- 只对业务逻辑层实施事务 --> <aop:pointcut id="txPointcut" expression="execution(* com.sz.sh.dal.dao.hibernate.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" /> </aop:config> <!--hibernate4必须配置为开启事务 否则 getCurrentSession()获取不到 --> <aop:config expose-proxy="true"> <aop:pointcut id="basePointcut" expression="execution(* com.sz.sh.dal.common.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="basePointcut" /> </aop:config> </beans>
项目目录结构:
基础DAO:
定义最基本的方法。
public interface BaseDAO<M extends java.io.Serializable, PK extends java.io.Serializable> { public PK save(M model); public void saveOrUpdate(M model); public void update(M model); public List<M> findByExample(M model); public List<M> findByCriterion(Criterion criterion, Order order, Integer offset, Integer length); public List<M> findByProperty(Map<String, Object> param, int offset, int length); public void merge(M model); public void delete(PK id); public boolean exists(PK id); public M get(PK id); public List<M> getALL(); public Long countALL(); }
基础DAO实现:核心的实现类
本抽象类中,实现了一些安主键查询,分页查询,添删改,等一些基本的操作。
而且,基本涵盖了一些常用的利用hibernate处理数据库的不同方法。
/** * @0 getSession().createQuery HQL查询 * @1 getSession().createSQLQuery NATIVE sql 查询 使用 NATIVE sql可能出现属性类型 * sess.createSQLQuery("SELECT * FROM CATS").addScalar("ID", Hibernate.LONG).addScalar("NAME") * sess.createSQLQuery("SELECT ID NAME, BIRTHDATE FROM CATS").addEntity(Cat.class * @2 getSession().createCriteria Criteria 查询 @ * * @param <M> * @param <PK> */ @MappedSuperclass public abstract class BaseDAOHib<M extends java.io.Serializable, PK extends java.io.Serializable> implements BaseDAO<M , PK>{ protected static final Logger LOGGER = LoggerFactory.getLogger(BaseDAOHib.class); private Class<M> entityClass; private String HQL_LIST_ALL; private String HQL_COUNT_ALL; private String pkName = "Id"; @SuppressWarnings("unchecked") public BaseDAOHib(){ this.entityClass = (Class<M>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; // TODO @Entity name not null HQL_LIST_ALL = "from " + this.entityClass.getSimpleName() + " order by " + pkName + " desc"; HQL_COUNT_ALL = " select count(*) from " + this.entityClass.getSimpleName(); } @Autowired @Qualifier("shSessionFactory") private SessionFactory sessionFactory; public Session getSession() { // 事务必须是开启的(Required),否则获取不到 return sessionFactory.getCurrentSession(); } @SuppressWarnings("unchecked") public PK save(M model) { return (PK) getSession().save(model); } public void saveOrUpdate(M model) { getSession().saveOrUpdate(model); } public void update(M model) { getSession().update(model); } public List<M> findByExample(M model) { List<M> results = getSession().createCriteria(this.entityClass).add(Example.create(model)).list(); return results; } public List<M> findByCriterion(Criterion criterion, Order order, Integer offset, Integer length) { Criteria criteria = getSession().createCriteria(this.entityClass); criteria.add(criterion); if (order != null) { criteria.addOrder(order); } if (offset != null) { criteria.setFirstResult(offset); } if (length != null) { criteria.setMaxResults(length); } return criteria.list(); } public List<M> findByProperty(Map<String, Object> param, int offset, int length) { StringBuffer queryString = new StringBuffer("from " + this.entityClass.getSimpleName() + " where "); List<Object> values = new ArrayList<Object>(); boolean firstparam = true; for (Map.Entry<String, Object> entry : param.entrySet()) { values.add(entry.getValue()); if (!firstparam) { queryString.append(" and "); } queryString.append(entry.getKey() + "= ? "); firstparam = false; } Query queryObject = getSession().createQuery(queryString.toString()); for (int i = 0; i < values.size(); i++) { queryObject.setParameter(0, values.get(i)); } return queryObject.list(); } public void merge(M model) { getSession().merge(model); } public void delete(PK id) { getSession().delete(this.get(id)); } public boolean exists(PK id) { return get(id) != null; } public M get(PK id) { return (M) getSession().get(this.entityClass, id); } public List<M> getALL() { return getSession().createQuery(HQL_LIST_ALL).list(); } public Long countALL() { return (Long) getSession().createQuery(HQL_COUNT_ALL).uniqueResult(); } }
具体对应表的DAO:注意继承BaseDAO 这样默认接口继承者实现基础类的共通方法。
public interface CategoryDAO extends BaseDAO<CategoryDO,Long>{ public List<CategoryDO> getAllCategory(); public CategoryDO getCategoryById(Long id); }
具体对应表的DAO接口继承者: 继承了基础DAO的实现,这样一来就不需要自己实现了。
如此就实现了,所有对应表的DAO都公用了一份基础DAO实现。大大的减少了DAO层的开发时间,降低了DAO层的bug率。
@Repository("categoryDAO") public class CategoryDAOHibernate extends BaseDAOHib<CategoryDO,Long> implements CategoryDAO{ @Override public List<CategoryDO> getAllCategory() { return super.getALL(); } @Override public CategoryDO getCategoryById(Long id) { return get(id); } }
另外贴上pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>work</groupId> <artifactId>Spring_Hibernate</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>Spring_Hibernate</name> <url>http://maven.apache.org</url> <profiles> <!-- 开发环境,默认激活 --> <profile> <id>dev</id> <properties> <env>dev</env> <maven.test.skip>true</maven.test.skip> </properties> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> </profiles> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring-version>3.1.1.RELEASE</spring-version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> </dependency> <!-- ================================================= --> <!-- Spring框架 --> <!-- ================================================= --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring-version}</version> </dependency> <!-- ================================================= --> <!-- Hibernate --> <!-- ================================================= --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.1.9.Final</version> </dependency> <!-- ================================================= --> <!-- 日志及相关依赖(用slf4j+logback代替jcl+log4j) --> <!-- ================================================= --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.1</version> </dependency> <!-- 将现有的jakarta commons logging的调用转换成lsf4j的调用。 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.6.1</version> </dependency> <!-- Hack:确保commons-logging的jar包不被引入,否则将和jcl-over-slf4j冲突 --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> <scope>provided</scope> </dependency> <!-- slf4j的实现:logback,用来取代log4j。更快、更强! --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>0.9.24</version> <scope>runtime</scope> </dependency> </dependencies> <build> <defaultGoal>install</defaultGoal> <filters> <filter>${user.dir}/env/filter-${env}.properties</filter> </filters> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> </build> </project>
让我们继续前行
----------------------------------------------------------------------
努力不一定成功,但不努力肯定不会成功。
共勉。