本文通过hibernate注解实现对象映射
一、viewspace-dao.xml配置
<!-- 扫描com.sunsharing.dao包下所有标注@Repository的DAO组件 --> <context:component-scan base-package="com.sunsharing.springdemo.dao"/> <!--使用spring提供的PropertyPlaceholderConfigurer读取数据库配置信息.properties--> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"/> </bean> <!--数据源配置--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"/> <!--SessionFactory接口负责初始化Hibernate,是重量级的,一般一个项目只要一个SessionFactory--> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="com.sunsharing.springdemo.domain"/> <property name="hibernateProperties"> <props> <!--<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>--> <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.use_second_level_cache">true</prop> <prop key="hibernate.cache.use_query_cache">true</prop> </props> </property> </bean> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate" p:sessionFactory-ref="sessionFactory" /> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="dataSource"/>
在此配置过程中遇到过两个问题:
1、数据源问题,参看网友的代码案例,引入spring(org.springframework.jdbc.datasource.DriverManagerDataSource) 的数据源,发现destroy-method="close"处报错,经过查证后发现,DriverManagerDataSource数据源不存在这个关闭的方法,后改用BasicDataSource 数据源解决。关于数据源介绍请参看
Spring学习总结3——配置datasource三种方式 ,在此不做累述。
2、maven 中Oracle驱动没有授权问题,不能够引入Oracle的驱动包,解决方法见
在Maven仓库中添加Oracle JDBC驱动(11g)
二、模型层的User POJO
package com.sunsharing.springdemo.domain; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import javax.persistence.*; /** * Created by nyp on 2015/2/5. */ @Entity @SequenceGenerator(name = "USER_ID_SEQUENCE",allocationSize=1,initialValue=1, sequenceName = "USER_ID_SEQUENCE") @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @Table(name = "T_USER") public class User extends BaseDomain { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_ID_SEQUENCE") @Column(name="USER_ID") private int userId; @Column(name="USER_NAME") private String userName; @Column(name="PASSWORD") private String password; @Column(name="LAST_IP") private String lastIp; @Column(name="LAST_VISIT") private String lastVisit; public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getLastIp() { return lastIp; } public void setLastIp(String lastIp) { this.lastIp = lastIp; } public String getLastVisit() { return lastVisit; } public void setLastVisit(String lastVisit) { this.lastVisit = lastVisit; } }
注解的过程中需要注意的是Oracle中的主键生成策略与mysql 有所差别,Oracle需要自己建立序列(sequence的好处主要是在数据库各种情况下,不会生成重复值,保证插入的唯一性)。
1.首先需要在实体类前面申明一个Sequence如下
方法:
@SequenceGenerator(name="SEQ_Name",sequenceName="SEQ_DB_Name")
参数注意:
SEQ_Name:表示为申明的这个Sequence指定一个名称,以便使用
SEQ_DB_Name:表示为数据库中的Sequence指定一个名称。两个参数的名称可以一样。
此时主键id的增长是按照hibernate自动处理的方式,而并非数据库中定义的sequence来处理。
必须加allocationSize=1,initialValue=1这两项配置才可以解决上述问题。
2.然后使用@GeneratedValue注解
方法:@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="SEQ_Name")
参数:
strategy:固定为GenerationType.SEQUENCE
Generator:在实体类前面申明的sequnce的名称
以上这部分就是对Oracle中的序列主键的详细注解说明了。
三、dao层java代码
首先是BaseDao 作为DAO基类
package com.sunsharing.springdemo.dao; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.HibernateTemplate; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.sql.SQLException; import java.util.List; /** * Created by nyp on 2015/2/9. */ /** * DAO基类,其它DAO可以直接继承这个DAO,不但可以复用共用的方法,还可以获得泛型的好处。 */ public class BaseDao<T>{ private Class<T> entityClass; @Autowired private HibernateTemplate hibernateTemplate; // 查询条件 private String hql; /** * 通过反射获取子类确定的泛型类 */ public BaseDao() { Type genType = getClass().getGenericSuperclass(); Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); entityClass = (Class) params[0]; } /** * 根据ID加载PO实例 * * @param id * @return 返回相应的持久化PO实例 */ public T load(Serializable id) { return (T) getHibernateTemplate().load(entityClass, id); } /** * 根据ID获取PO实例 * * @param id * @return 返回相应的持久化PO实例 */ public T get(Serializable id) { return (T) getHibernateTemplate().get(entityClass, id); } /** * 获取PO的所有对象 * * @return */ public List<T> loadAll() { return getHibernateTemplate().loadAll(entityClass); } /** * 保存PO * * @param entity */ public void save(T entity) { getHibernateTemplate().save(entity); } /** * 删除PO * * @param entity */ public void remove(T entity) { getHibernateTemplate().delete(entity); } /** * 更改PO * * @param entity */ public void update(T entity) { getHibernateTemplate().update(entity); } /** * 执行HQL查询 * * @param sql * @return 查询结果 */ public List find(String hql) { return this.getHibernateTemplate().find(hql); } /** * 执行带参的HQL查询 * * @param sql * @param params * @return 查询结果 */ public List find(String hql, Object... params) { return this.getHibernateTemplate().find(hql,params); } /** * 对延迟加载的实体PO执行初始化 * @param entity */ public void initialize(Object entity) { this.getHibernateTemplate().initialize(entity); } public HibernateTemplate getHibernateTemplate() { return hibernateTemplate; } }
UserDao中java代码
package com.sunsharing.springdemo.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowCallbackHandler; import org.springframework.stereotype.Repository; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; /** * Created by nyp on 2015/2/5. */ @Repository public class UserDao extends BaseDao<User> { private final String GET_USER_BY_USERNAME = "from User u where u.userName = ?"; private final String QUERY_USER_BY_USERNAME = "from User u where u.userName like ?"; //注意上面的User表示的是User对象 @Autowired private JdbcTemplate jdbcTemplate; /** * 根据用户名查询User对象 * @param userName 用户名 * @return 对应userName的User对象,如果不存在,返回null。 */ public User getUserByUserName(String userName){ List<User> users = (List<User>)find(GET_USER_BY_USERNAME,userName); if (users.size() == 0) { return null; }else{ return users.get(0); } } /** * 根据用户名为模糊查询条件,查询出所有前缀匹配的User对象 * @param userName 用户名查询条件 * @return 用户名前缀匹配的所有User对象 */ public List<User> queryUserByUserName(String userName){ return (List<User>)find(QUERY_USER_BY_USERNAME,userName+"%"); } }
四、junit测试代码
package com.sunsharing.springdemo.dao; import com.sunsharing.springdemo.domain.User; import com.sunsharing.component.utils.base.DateUtils; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import java.util.Date; import java.util.Iterator; import java.util.List; import static org.testng.Assert.*; /** * Created by nyp on 2015/2/5. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:/viewspace-dao.xml"}) public class UserDaoTest{ @Autowired private UserDao userDao; @Test public void findALLUserByHibernate() { List<User> list = userDao.loadAll(); System.out.println("list="+list); Iterator<User> it=list.iterator(); while(it.hasNext()){ User u=it.next(); System.out.println("name="+u.getUserName()); } } @Test public void findUserByIdHibernate() { User user= userDao.get(70); System.out.println("user:"+user.getUserName()); assertNotNull(user); assertEquals(user.getUserName(), "admin"); } @Test public void addUserByHibernate(){ DateUtils.transFormat(new Date(),"yyyyMMddHHmmss"); System.out.println("date="+DateUtils.transFormat(new Date(), "yyyyMMddHHmmss")); User user=new User(); user.setUserName("HibernateTest15"); user.setPassword("123456"); user.setLastVisit(DateUtils.transFormat(new Date(), "yyyyMMddHHmmss")); user.setLastIp("255.255.255.255"); userDao.save(user); assertEquals(user.getPassword(),"123456"); } }
在此过程中比较头疼的就是Oracle中的date在hibernate中的映射问题
oracle结合hibernate 时日期类型报
java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff] at java.sql.Timestamp.valueOf(Timestamp.java:235) at oracle.jdbc.driver.CharCommonAccessor.getTimestamp(CharCommonAccessor.java:544) at oracle.jdbc.driver.T4CCharAccessor.getTimestamp(T4CCharAccessor.java:862) at oracle.jdbc.driver.OracleResultSetImpl.getTimestamp(OracleResultSetImpl.java:1422) at oracle.jdbc.driver.OracleResultSet.getTimestamp(OracleResultSet.java:516) at org.apache.commons.dbcp.DelegatingResultSet.getTimestamp(DelegatingResultSet.java:262) at org.hibernate.type.descriptor.sql.TimestampTypeDescriptor$2.doExtract(TimestampTypeDescriptor.java:62) at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:64) at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:254) at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:250) at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:230) at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:331) at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2283) at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1527) at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1455) at org.hibernate.loader.Loader.getRow(Loader.java:1355) at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:611) at org.hibernate.loader.Loader.doQuery(Loader.java:829) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274) at org.hibernate.loader.Loader.doList(Loader.java:2542) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276) at org.hibernate.loader.Loader.list(Loader.java:2271) at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119) at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1716) at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347) at org.springframework.orm.hibernate3.HibernateTemplate$5.doInHibernate(HibernateTemplate.java:590) at org.springframework.orm.hibernate3.HibernateTemplate$5.doInHibernate(HibernateTemplate.java:1) at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406) at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374) at org.springframework.orm.hibernate3.HibernateTemplate.loadAll(HibernateTemplate.java:584) at com.sunsharing.springdemo.dao.BaseDao.loadAll(BaseDao.java:56) at com.sunsharing.springdemo.dao.TesthTest.findUserByHibernate(TesthTest.java:23) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:292) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
注解配置那边有加这些:@Temporal(value = TemporalType.TIMESTAMP)
private Date user_date;(Date引的是java.util.date;oracle 数据库那边用的是char(34))
问题解决:此问题是由POJO中对应Oracle 中的char字段导致,把char改为date 即可。
此为一种解决方法,但结合实际开发,并不一定都这么用。另外一种解决方法为就是数据库中的日期用char,而模型层中对应的属性用String类型即可。(上面给出的源码即为次种解决方案)
最后补充下SQL语句:
CREATE SEQUENCE user_id_sequence INCREMENT BY 1 -- 每次加几个 START WITH 1 -- 从1开始计数 NOMAXVALUE -- 不设置最大值 NOCYCLE -- 一直累加,不循环 NOCACHE; --不缓存 --创建用户表 CREATE TABLE t_user ( user_id NUMBER(6) primary key, user_name VARCHAR2(30), password VARCHAR2(32), last_visit CHAR(28), last_ip VARCHAR2(23) ); insert into t_user(USER_ID,U_TYPE,LOGIN_ID,NAME,PWD,DEL,CREATE_TIME,UPDATE_TIME) values(USER_ID_SEQUENCE.NEXTVAL,1,'admin','管理员','123456',0,sysdate, sysdate);