在没有将spring和hibernate整合在一起的时候,要使用hibernate,在持久层需要如下步骤:
一、在还没有对hibernate进行spring的整合的时候,我们需要写一个session工具类来产生sssion操作数据库
SessionUtil.java类:
package com.ge.hibernatexml.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class SessionUtil {
private static Configuration cfg;
private static ServiceRegistry serviceRegistry;
private static SessionFactory sessionFactory;
private static ThreadLocal<Session> local = new ThreadLocal<Session>() {
protected Session initialValue() {
return sessionFactory.openSession();
};
};
static {
cfg = new Configuration().configure();
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
cfg.getProperties()).build();
sessionFactory = cfg.buildSessionFactory(serviceRegistry);
}
public static Session getSession() {
Session session = local.get();
if(session == null) {
session = sessionFactory.openSession();
local.set(session);
}
return session;
}
}
二、然后利用切面进行事务的的管理:
TransactionAspect.java类:
package com.ge.hibernatexml.aspect;
import java.lang.reflect.Field;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.stereotype.Component;
import com.gezhi.hibernatexml.util.SessionUtil;
@Component
@Aspect
public class TransactionAspect {
private Transaction tx;
/**
* 定义切入点表达式
*/
@Pointcut("execution(* com.ge.hibernatexml.*mag.dao.impl.*Impl.*(..))")
public void pointcut() {}
/**
* 定义前置通知
* @param join
*/
@Before("pointcut()")
public void beforeAdvice(JoinPoint join) {
Session session = SessionUtil.getSession();
Object obj = join.getTarget();//得到目标对象
Class<?> cls = obj.getClass();
try {
Field field = cls.getDeclaredField("session");
field.setAccessible(true);
field.set(obj, session);
//开启该session对应的事务操作能力
tx = session.beginTransaction();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@AfterReturning(pointcut="pointcut()",returning="rev")
public void afterReturningAdvice(JoinPoint join,Object rev) {
tx.commit();
}
@AfterThrowing(pointcut="pointcut()",throwing="e")
public void afterThrowingAdvice(JoinPoint join,Exception e) {
tx.rollback();
}
}
三、在spring的配置文件applicationContext.xml中要开启切面支持:
<!-- 开启切面的动态代理支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
下面就可以进行数据库的操作了。
一、对于增删改,可以直接调用hibernate内置的方法进行调用,操作底层数据库:
@Repository
public class UserDaoImpl implements IUserDao {
private Session session;
@Override
public void saveUserBean(UserBean user) {
// TODO Auto-generated method stub
session.save(user);
}
@Override
public void updateUserBean(UserBean user) {
// TODO Auto-generated method stub
session.update(user);
}
@Override
public void deleteUserBean(UserBean user) {
// TODO Auto-generated method stub
session.delete(user);
}
}
二、对于查询而言,他有两个方法(get和load)是根据id进行数据查询
@Repository
public class UserDaoImpl implements IUserDao {
private Session session;
@Override
public UserBean getUserBeanById(int id) {
// TODO Auto-generated method stub
return (UserBean) session.get(UserBean.class, id);
}
/**
*
*/
@Override
public UserBean loadUserBeanById(int id) {
// TODO Auto-generated method stub
/*
* get()和load()的区别: get()在查询对象时,采用的是即时查询方法,它从一级缓存开始,进行二级缓存,到达数据库,它一定会得到一个最终的结果。
* load()在查询对象时,采用的是延迟查询方法,它从一级缓存开始,进行二级缓存,如果二级缓存中没有对应的数据,它将默认数据库中一定存在那条数据,
* 并返回该对象的代理对象, 直到程序发生调用时,才去查询,找到了就正常返回,找不到,抛异常:ObjectNotFoundException
*/
// 延迟加载对象,一定不能关闭Session
return (UserBean) session.load(UserBean.class, id);
}
}
三、自定义查询语句
- 通过查询id返回一个Map数据(用?进行预编译的形式)
@Override
public Map<String, Object> queryUserBeanById(Integer id) {
// TODO Auto-generated method stub
String hql = "select new map(u.userName as userName,u.loginName as loginName,u.password as password) From UserBean as u where id = ?";
Query query = session.createQuery(hql);
query.setInteger(0, id);
List<?> datas = query.list();
if (datas != null)
return (Map<String, Object>) datas.get(0);
return null;
}
在hibernate中,我们可以使用两种方式来进行自定义语句的编写,第一种,利用hql语句。
从上面可以看到,hql语句和sql语句有一些区别,因为是面对对象编程了,所以UserBean对应了t_user;
通过map来接收指定的一些数据,那么就会以hql语句中map中的别名作为键,具体查出来的值为具体的值进行返回;
createQuery(hql)是执行hql的语句的预编译,返回一个Query类型的查询接口,同过这个接口对预编译的语句进行赋值,默认第一个?的位置是0。
query.list()是执行查询结果,返回一个list集合的结果集,因为这里通过id只能查询出一条结果,所以,用list的get方法,get(0)就可以获得这条数据。
- 通过查询对象返回一个Map类型的list集合(通过取别名“:参数名”的形式进行预编译)
@Override
public List<Map<String, Object>> findUserBeanMapByObject(UserBean user) {
// TODO Auto-generated method stub
String hql = "select new map(u.loginName,u.userName,u.age) From UserBean as u where u.userName like concat(:userName,'%') and u.gender = :gender";
Query query = session.createQuery(hql);// 产生一个Query接口的实例,并针对HQL进行预编译
query.setProperties(user);
return query.list();
}
通过取别名的方式来代替?,从hql语句中我们可以看到,我们传进来是一个对象,那么只要我们的对象属性的名称和hql语句中需要赋值的字段的名字保持一致就可以了,用“ :参数名”来替代上面预编译的问号,就是“:”后面的参数名与对象属性一致,这样我们就可以直接用query.setProperties(对象) 的形式进行赋值了。
如果我们用的“ :参数名”没有和对象的属性的名称对应,那么就需要如下这种方式了进行赋值(别名赋值):
@Override
public UserBean findUserBeanByLoginNameAndPwd(String loginName, String pwd) {
// TODO Auto-generated method stub
/*
* 按照参数别名进行设值
*/
String hql = "From UserBean as u where u.loginName = :ln and u.password = :pwd";
Query query = session.createQuery(hql);// 产生一个Query接口的实例,并针对HQL进行预编译
query.setString("ln", loginName);
query.setString("pwd", pwd);
List<?> datas = query.list();
if (datas != null)
return (UserBean) datas.get(0);
return null;
}
hql语句省略了前面的select部分,默认返回的是表关联对象的集合,这里就是UserBean的集合。
如果用?来进行预编译,就用下标形式赋值:
// select * from t_user as u where u.login_name = ? and u.user_pwd = ?
// 按照位置进行设值
String hql = "From UserBean as u where u.loginName = ? and u.password = ?";
Query query = session.createQuery(hql);//产生一个Query接口的实例,并针对HQL进行预编译
query.setString(0, loginName);//在JDBC中,第1个?下标是1,在Hibernate中,下标是0
query.setString(1, pwd);
List<?> datas = query.list();