培训第31天----Hibernate初识(2)

                不知不觉已经培训一个月了,时间过的好快。。。。。

                嘻嘻嘻,下面我主要说两个知识点。一,不用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;
	}
}

二.两表联查      

               我们知道,两个表能够联查的前提条件是 一个表的主键,指向一个表的外键。这就出现一个问题,例如:

扫描二维码关注公众号,回复: 3034527 查看本文章

既然一个表的主键指向一个表的外键,那么就说明这两个表中就都有这个主键字段,相应的,对应表的实体类也

就都有这个主键的属性。这两个实体类都有相同的属性,这就重复了,那么应该删除掉哪一个实体类中的主键属

性呢?因为在多对一的情况下,一般都是一的一方拥有主键,多的一方拥有外键。所以我们要删除掉多的一方的主

键属性(原谅我水平低下,实在不知道怎么表达)。

               然后,我们就要在两个实体类中封装对方的对象,并生成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()方法的时候,不要输出对象属性,因为这样会造成栈内存溢出

(循环调用)。

猜你喜欢

转载自blog.csdn.net/qq_41160264/article/details/81710325