【内容】
1. 牧羊人、DAO模式和Bba96模块
我们常常在讲述J2EE的技术文章中看到这样的举例:“对一个牧场主而言,他要管理整个农场,事情太多了,因此让他亲自管理1000只羊的羊群是非常困难的。因此,他找了一个专职的牧羊人专门管理这些羊,而他只需牧羊人打交道,就达成了对羊群的管理。”
这实际上是DAO(Date Access Object,数据存取对象)设计模式的一个现实情景:既然可以用“牧羊人”将“羊群”与“牧场主”隔离开,“牧场主”通过“牧羊人”达成对“羊群”的管理,那么,类似的我们可以用“DAO”将“数据库”与“业务逻辑”隔离开,使得“业务逻辑”用“DAO”就可以实现对“数据库”的存取。
在系统中,使用“dao模式”设计有以下优势:
1) 简化了业务逻辑的设计:将复杂的数据存取代码从业务逻辑中分离出来,降低了业务逻辑中的代码的复杂性,可以将注意力更多地集中在业务逻辑的处理上。
2) 增强了代码的复用性、可维护性和可靠性:数据存取代码集中地封装到DAO中,可以集中、全面、完整地考虑DAO的数据存取解决方案,代码的维护也比较集中。
3) 提高了系统的可移植性:因为业务逻辑和底层的数据源没有直接关联,因此,数据源的切换不会导致业务逻辑的修改。
Bba96模块在整个系统中所扮演的恰恰就是“牧羊人”的角色,它主要负责系统对数据库的访问。
u Bba96的下载地址:http://bba96.dev.java.net
2. 与Spring的整合配置
<?xml version="1.0" encoding="UTF-8"?>
<!--系统数据源及实体类配置-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!--定义数据源及数据连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass">
<value>${dataSource.driverClassName}</value>
</property>
<property name="jdbcUrl">
<value>${dataSource.url}</value>
</property>
<property name="user">
<value>${dataSource.username}</value>
</property>
<property name="password">
<value>${dataSource.password}</value>
</property>
<!--连接池中保留的最小连接数。-->
<property name="minPoolSize">
<value>5</value>
</property>
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize">
<value>30</value>
</property>
<!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
<property name="initialPoolSize">
<value>10</value>
</property>
<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime">
<value>60</value>
</property>
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement">
<value>5</value>
</property>
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
<property name="maxStatements">
<value>0</value>
</property>
<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">
<value>60</value>
</property>
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts">
<value>30</value>
</property>
<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
<property name="breakAfterAcquireFailure">
<value>true</value>
</property>
<!--因性能消耗大,请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable等方法来提升连接测试的性能。Default: false -->
<property name="testConnectionOnCheckout">
<value>false</value>
</property>
</bean>
<!-- 实体类列表 -->
<bean id="entityList" class="java.util.ArrayList">
<constructor-arg>
<list>
<value>com.cn.entity.Authority</value>
<value>com.cn.entity.SpecialBase</value>
<value>com.cn.entity.SpecialBase_MediaBase</value>
<value>com.cn.entity.MediaBase</value>
<value>com.cn.entity.MediaTransmit</value>
<value>com.cn.entity.MediaSend</value>
<value>com.cn.entity.ServiceBase</value>
<value>com.cn.entity.UserBase</value>
<value>com.cn.entity.UserBase_Authority</value>
<value>com.cn.entity.UserCommon</value>
</list>
</constructor-arg>
</bean>
<!--SessionFactory定义-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--定义以Annotation方式配置-->
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
<!--Hibernate属性定义-->
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">
${sessionFactory.hibernateProperties.hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">
${sessionFactory.hibernateProperties.hibernate.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.characterEncoding">GBK</prop>
<prop key="hibernate.connection.release_mode">auto</prop>
<prop key="hibernate.query.substitutions">true 1, false 0, yes 'Y', no 'N'</prop>
<prop key="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</prop>
<prop key="hibernate.jdbc.batch_size">25</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.use_streams_for_binary">true</prop>
<prop key="hibernate.max_fetch_depth">1</prop>
<prop key="hibernate.cache.use_minimal_puts">true</prop>
<prop key="hibernate.use_outer_join">true</prop>
<prop key="hibernate.prepare_sql">true</prop>
<prop key="current_session_context_class">thread</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.OSCacheProvider</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">oscache.properties</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_structured_entries">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
<prop key="hibernate.generate_statistics">false</prop>
</props>
</property>
<!--hiberante事件监听列表-->
<property name="eventListeners">
<map>
<entry key="merge">
<bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener" />
</entry>
</map>
</property>
<!--实体类列表-->
<property name="annotatedClasses" ref="entityList" />
</bean>
<!--Hibernate事务管理器-->
<bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<!--事务拦截器定义-->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="hibernateTransactionManager" />
<!--定义事务属性源:由标准@Transactional获取-->
<property name="transactionAttributeSource">
<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource" />
</property>
</bean>
<!--代理自动生成器:将历遍上下文中的Advisor-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<!--强制使用CGLIB生成代理而不使用接口-->
<property name="proxyTargetClass" value="true" />
<!--强制使Advisor一旦装备就不再改变-->
<property name="frozen" value="true" />
</bean>
<!--事务属性装配Advisor-->
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor" ref="transactionInterceptor" />
</bean>
<!--bba96实体类操作模块-->
<bean id="hibernateDao" class="com.bba96.core.dao.hibernate.HibernateDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!--bba96实体类操作模块-->
<bean id="entityManager" class="com.bba96.core.service.DefaultEntityManager">
<property name="dao" ref="hibernateDao" />
</bean>
</beans>
3. BBA96和daoModule查询效率的对比
测试一:select * from userbase分页查询
模块 | 写法 | 时间 |
hibernateDao | QueryObject obj = new QueryObjectBase(); obj.setEntityClass(UserBase.class); obj.setQueryParam(new QueryParam()); int pageSize = 24; Page page = new Page(); page = hibernateDAO. findByQueryObject(obj, true, 0 * pageSize, pageSize, true); list = page.getList(); | 109 |
daoModule | list=daoModule.listByHQL("from UserBase"); | 312 |
daoModule | PageModule page= daoModule.listForPagesByHQL("from UserBase","userId",24,0); list=page.getPageList(); | 328 |
daoModule | list=daoModule.listByAll("com.cn.entity.UserBase"); | 156 |
测试二:insert into userbase (passWord, userName) values (?, ?)插入数据
模块 | 写法 | 时间 |
hibernateDao | hibernateDAO.save(user); | 31 |
daoModule | daoModule.insert(user); | 171 |
4. 几种常见的数据查询方式
a) ById查询:在系统中有两种不同的写法,分别使用hibernateDao和entityManager两个模块,它们都是bba96的组成部分。
i. 写法一:
public void testLisyById() {
UserBaseAction action = (UserBaseAction) super.getApplicationContext().getBean("userBaseAction");
UserBase user = action.listById("402886e51eb1ae85011eb1aeaa7c0033");
logger.debug("username="+user.userName);
}
ii. 写法二:
public UserBase listById(String userId) {
UserBase userBase =
entityManager.getById(UserBase.class, userId);
return userBase;
}
b) Count查询
public int listCount() {
QueryParam param=new QueryParam();
param.or(new QueryParam("userName",QueryParam.OPERATOR_EQ,"abcd"));
param.or(new QueryParam("userName",QueryParam.OPERATOR_EQ,"4986bd40"));
int count=entityManager.count(UserBase.class, param, true);
return count;
}
c) OR条件查询
public Page<?> listByOr() {
QueryObject<UserBase> queryObject = new QueryObjectBase<UserBase>();
queryObject.setEntityClass(UserBase.class);
QueryParam queryParam1 = new QueryParam("userName",
QueryParam.OPERATOR_EQ, "abcd");
QueryParam queryParam2 = new QueryParam("userName",
QueryParam.OPERATOR_EQ, "4986bd40");
QueryParam queryParam = new QueryParam();
queryParam.or(queryParam1);
queryParam.or(queryParam2);
queryObject.setQueryParam(queryParam);
// Page<?> page = super.hibernateDao.findByQueryObject(queryObject,
// true,
// pageNum * pageSize, pageSize, true);
Page<?> page = entityManager.find(UserBase.class, queryParam, pageNum
* pageSize, pageSize);
return page;
}
d) AND条件查询
public Page<?> listByAnd() {
QueryObject<UserBase> queryObject = new QueryObjectBase<UserBase>();
queryObject.setEntityClass(UserBase.class);
QueryParam queryParam1 = new QueryParam("userName",
QueryParam.OPERATOR_EQ, "abcd");
QueryParam queryParam2 = new QueryParam("passWord",
QueryParam.OPERATOR_EQ, "abcd");
QueryParam queryParam = new QueryParam();
queryParam.and(queryParam1);
queryParam.and(queryParam2);
queryObject.setQueryParam(queryParam);
// Page<?> page = super.hibernateDao.findByQueryObject(queryObject,
// true,
// pageNum * pageSize, pageSize, true);
Page<?> page = entityManager.find(UserBase.class, queryParam, pageNum
* pageSize, pageSize);
return page;
}
e) 排序查询
public void testLisyByOrder() {
UserBaseAction action = (UserBaseAction) super.applicationContext.getBean("userBaseAction");
Page<?> page = action.listByOrder();
List<?> list = page.getList();
for (int i = 0; i < list.size(); ++i) {
UserBase user = (UserBase) list.get(i);
logger.debug("username=" + user.userName + "(pageNum="
+ action.pageNum + ";pageSize=" + action.pageSize + ")");
}
}
f) 通过SQL语句的查询
public Page<?> listBySql() {
String sql = "select * from userbase where username='param1' or username='param2'";
sql.replaceAll("param1", "abcd").replaceAll("param2", "4986bd40");
String alias = "sqls";
Page<?> page = super.hibernateDao.findBySQL(sql, alias, UserBase.class, true, pageNum * pageSize, pageSize, null);
return page;
}