在沒有將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();