不知不觉已经培训一个月了,时间过的好快。。。。。
嘻嘻嘻,下面我主要说两个知识点。一,不用sql语句的查询。二,将两个表关联起来。
一.不用sql语句的查询
昨天写的获得SessionFactory的类属实有些不规范,今天用MyEclipse自动生成了获得SessionFactory的
工具类,如下:
package com.java.Utils;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
/**
* Configures and provides access to Hibernate sessions, tied to the
* current thread of execution. Follows the Thread Local Session
* pattern, see {@link http://hibernate.org/42.html }.
*/
public class HibernateSessionFactory {
/**
* Location of hibernate.cfg.xml file.
* Location should be on the classpath as Hibernate uses
* #resourceAsStream style lookup for its configuration file.
* The default classpath location of the hibernate config file is
* in the default package. Use #setConfigFile() to update
* the location of the configuration file for the current session.
*/
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static Configuration configuration = new Configuration();
private static org.hibernate.SessionFactory sessionFactory;
private static String configFile = CONFIG_FILE_LOCATION;
static {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
/*私有化构造方法优先思考单例设计模式*/
private HibernateSessionFactory()
{
}
/**
* Returns the ThreadLocal Session instance. Lazy initialize
* the <code>SessionFactory</code> if needed.
*
* @return Session
* @throws HibernateException
*/
public static Session getSession() throws HibernateException
{
/*确保当前线程中session的唯一性*/
Session session = (Session) threadLocal.get();
/*如果当前线程中session是空的或者为关闭的*/
if (session == null || !session.isOpen())
{
/*构建一个新的session*/
/*由于session是由sessionFactory产生的,因此需要判断sessionFactory的状态*/
if (sessionFactory == null)
{
/*重新读取一次配置文件进行构建sessionFactory*/
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession(): null;
/*再次放到线程中 */
threadLocal.set(session);
}
return session;
}
/**
* Rebuild hibernate session factory
*
*/
public static void rebuildSessionFactory() {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
/**
* Close the single hibernate session instance.
*
* @throws HibernateException
*/
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
/**
* return session factory
*
*/
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
/**
* return session factory
*
* session factory will be rebuilded in the next call
*/
public static void setConfigFile(String configFile) {
HibernateSessionFactory.configFile = configFile;
sessionFactory = null;
}
/**
* return hibernate configuration
*
*/
public static Configuration getConfiguration() {
return configuration;
}
}
但是,自己写的时候需要用try-catch的地方,eclipse却没有提示我要捕获异常,所以也就出现了自己写的
版本的SessionFactory工具类,如下。。。。:
package com.java.Utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
//获取session的工具类
public class HibernateSessionFactory_i {
//静态变量
private static String CONFIG_FILE_LOCATION="/hibernate.cfg.xml";
private static Configuration configuration=new Configuration();
private static SessionFactory sessionFactory;
private static String configFile=CONFIG_FILE_LOCATION;
private static final ThreadLocal<Session> threadLocal=new ThreadLocal<Session>();
//为变量进行初始化
static {
Configuration configure = configuration.configure(configFile); //读取配置文件
sessionFactory=configuration.buildSessionFactory(); //创建sessionFactory
}
private HibernateSessionFactory_i() {
//私有化构造方法,首先想到的是单例设计模式
}
public static Session getSession(){
Session session=threadLocal.get();
if(session==null || !session.isOpen()) {
//为了减少异常,要判断SessionFactory是否为空
if(sessionFactory==null) {
//重新读取一次配置文件,来获得SessionFactory对象
rebuildSessionFactory();
}
session=(sessionFactory!=null) ? sessionFactory.openSession():null;
}
return session;
}
public static void rebuildSessionFactory() {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
}
public static void closeSession() {
Session session=threadLocal.get();
threadLocal.set(null);
if(session!=null) {
session.close();
}
}
public static Configuration getConfiguration() {
return configuration;
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void setConfigFile(String configFile) {
//更改配置文件路径,并将依赖配置文件生成的SessionFactory置为null
HibernateSessionFactory_i.configFile = configFile;
sessionFactory = null;
}
}
其中实体类,核心配置文件,映射配置文件等和昨天的一样,这里就不再叙述。
下面是在Hibernate中用原生态的sql语句来查询,并返回一个集合对象。可以看到,这种方式非常麻烦。
package com.java.DaoImp;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import com.java.Bean.User;
import com.java.Dao.UserDao;
import com.java.Utils.HibernateSessionFactory_i;
public class UserDaoImpl implements UserDao{
//不按照条件查询user信息
@Override
public List<User> query_SQLQuery(){
//用session对象来操作数据库
Session session=HibernateSessionFactory_i.getSession();
SQLQuery sqlQuery = session.createSQLQuery("select * from t_user");
List<Object[]> list=(List<Object[]>)sqlQuery.list();
List<User> list_user=new ArrayList<User>();
for(Object[] object:list) {
//手动创建对象,并将属性放到对象中返回
User user = new User();
for(int i=0;i<object.length;i++) {
if(i==0) {
user.setUserId(object[i].toString());
}
if(i==1) {
user.setUserName(object[i].toString());
}
if(i==2) {
user.setUserPassword(object[i].toString());
}
if(i==3) {
user.setUserSex(object[i].toString());
}
if(i==4) {
user.setUserRole(object[i].toString());
}
if(i==5) {
user.setUserCollege(object[i].toString());
}
if(i==6) {
user.setUserMajor(object[i].toString());
}
if(i==7) {
user.setUserClass(object[i].toString());
}
if(i==8) {
user.setDormitoryId(object[i].toString());
}
list_user.add(user);
}
}
//关闭线程中唯一的session
HibernateSessionFactory_i.closeSession();
return list_user;
}
//用框架进行查询,查询结果为多个,不用写sql语句
@Override
public List<User> query_Queqy_list(User user){
return null;
}
//用框架进行查询,查询结果为一个
@Override
public List<User> query_Queqy_one(User user){
return null;
}
}
下面是用Criteria查询对象来对数据库进行查询,这样就可以将注意力放在业务逻辑上,而不需要为繁重的sql语句
而分散注意力。
package com.java.DaoImp;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import com.java.Bean.User;
import com.java.Dao.UserDao;
import com.java.Utils.HibernateSessionFactory_i;
public class UserDaoImpl_criteria implements UserDao{
//用框架进行查询,查询结果为多个,不用写sql语句
@Override
public List<User> query_Queqy_list(User user){
return null;
}
//用框架进行查询,查询结果为一个
@Override
public List<User> query_Queqy_one(User user){
return null;
}
//使用Hibernate的Criteria进行无sql语句的无条件查询
@Override
public List<User> query_SQLQuery() {
/**
* Criteria条件查询
* sql:sql如果是过于复杂的那么同时书写java代码以及sql语句容易出现错误
* hql:高度封装sql使得开发者直接操作类,但是还是无法避免写一些简单的sql语句
* criteria:完全避免了sql语句的使用,全部转换成java代码进行开发
*/
//获取session对象
Session session =HibernateSessionFactory_i.getSession();
//通过session获取Criteria查询对象
Criteria criteria = session.createCriteria(User.class); //参数的意义是,查询这个类所映射的表
//调用方法来获得查询结果
List list=criteria.list();
//关闭session对象
HibernateSessionFactory_i.closeSession();
return list;
}
//在实现类中定义接口中未定义的方法
public List<User> criteria_query_byId(User user){
Session session=HibernateSessionFactory_i.getSession();
Criteria criteria=session.createCriteria(User.class);
//在用add方法后所得到的类型仍然是Criteria类型
Criteria add = criteria.add(Restrictions.eq("userId",user.getUserId()));
List list=add.list();
return list;
}
public User criteria_query_byId_byPassword(User user) {
Session session=HibernateSessionFactory_i.getSession();
Criteria criteria=session.createCriteria(User.class)
.add(Restrictions.eq("userSex",user.getUserSex()))
.add(Restrictions.eq("userRole",user.getUserRole()));
User user_return=(User)criteria.uniqueResult(); //该方法的返回值类型为Object,要强转为User类型
return user_return;
}
}
二.两表联查
我们知道,两个表能够联查的前提条件是 一个表的主键,指向一个表的外键。这就出现一个问题,例如:
既然一个表的主键指向一个表的外键,那么就说明这两个表中就都有这个主键字段,相应的,对应表的实体类也
就都有这个主键的属性。这两个实体类都有相同的属性,这就重复了,那么应该删除掉哪一个实体类中的主键属
性呢?因为在多对一的情况下,一般都是一的一方拥有主键,多的一方拥有外键。所以我们要删除掉多的一方的主
键属性(原谅我水平低下,实在不知道怎么表达)。
然后,我们就要在两个实体类中封装对方的对象,并生成get,set方法。代码如下:
虽然我们在两个实体类 中互相封装了用于存放对方的属性,但是还是要在 .hbm.xml 中配置响应的信息,
来告诉数据库我是两表联查的。
首先先配置多的一方(many)。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.zf.bean.User" table="t_user">
<id name="userId" column="userid" ></id>
<property name="userPwd" column="userpwd"></property>
<property name="userName" column="username"></property>
<property name="userSex" column="usersex"></property>
<property name="userRole" column="userrole"></property>
<property name="userCollege" column="usercollege"></property>
<property name="userMajor" column="usermajor"></property>
<property name="userClass" column="userclass"></property>
<!-- 既然在多的一方,删除掉了外键,那么相应的在配置文件中,也要把那列去掉-->
<many-to-one name="dormitory" lazy="false">
<column name="dormitoryid"></column>
</many-to-one>
<!-- 上面这段代码,name属性是封装的 one对象 的 变量,
column 中的name属性是many 的外键。
-->
</class>
</hibernate-mapping>
在配置一的一方(one)。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.zf.bean.Dormitory" table="t_dormitory">
<id name="dormitoryId" column="dormitoryid"></id>
<property name="planPersons" column="planpersons"></property>
<property name="realPersons" column="realpersons"></property>
<property name="waterPrice" column="waterprice"></property>
<property name="powerPrice" column="powerprice"></property>
<property name="grade" column="grade"></property>
<set name="users" lazy="false">
<key column="dormitoryid" ></key>
<one-to-many class="com.zf.bean.User"/>
</set>
<!-- 上面这段代码中 name属性的值应该是存放对象的set集合变量名,class
属性值应该是所要封装的对象属性的url。
column属性值应该是表中的主键字段。
-->
</class>
</hibernate-mapping>
上述代码中,都有一个lazy属性,可以将它设为true或者false。但是,在many一方这个lazy属性却只能设置为
false,因为这个属性是延迟加载的意思,也就是我要遍历的时候,才向数据库查询。因为是多的一方,所以当查询
many的时候确定只会有一个one出现,这个one不影响查询的速度(或者说影响可以忽略不记)。但是在one一方,
查询一个one的时候,会有很多个数据(many),所以就要用这个lazy属性,当在one的一方设为ture时,就是延迟
加载,当关闭Session后,将不能遍历many,但是当设为false时,即使关闭Session,也可以遍历many。因为它已
经查询出来了。(这篇博客写的我。。。。。,觉得自己好菜)
还有一点就是,在实体类中,重写toString()方法的时候,不要输出对象属性,因为这样会造成栈内存溢出
(循环调用)。