论坛首页 Java企业应用论坛

况家娃Hibernate一步一步学习笔记(01)

浏览 2661 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-05-15  

  很早就接触过Hibernate,可由于项目组中一直没有对Hibernate调优特别精通的牛人,所以后来做的系统大多因为是遗留系统,最终还是放弃了Hibernate,转而采用JDBC+连接池+Apache dbUtil等灵活的方法,自己控制连接池连接的关闭,使用dbUtil实现批量操作,效率也还是凑合的。今年换了一家公司,做产品,其中大量用到了Hibernate,我也早认为有必要好好学习一下Hibernate,于是把学习的心得帖出来,希望和想学Hibernate的朋友们一起进步,共同成长。老鸟看见我们有什么错误,欢迎斧正,不吝赐教,可千万别笑话我们呵呵。

  好了言归正传,我的第一个HibernateDemo:
  打开Eclipse,我用的是MyEclipse插件,加入【图一】(图一见页尾)所示的jar包到构建路径。注:我用的是Mysql数据库,相应的数据库Jar是mysql-connector-java-5.1.6-bin.jar,可以在MySql网站下载最新版。

1)新建数据库Table

CREATE TABLE `user` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(100) NOT NULL default '',
  `age` int(11) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


注:
    关于Mysql表类型,这里为了方便后期使用事务,用了InnoDB型。下面查到了一点参考,以后再遇到时,再详细探讨。

http://blog.csdn.net/hzsasheng/archive/2007/08/04/1725700.aspx 写道
MyISAM:
这个是Mysql表的默认类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法.与其他存储引擎比较,MyISAM具有检查和修复表格的大多数工具. MyISAM表格可以被压缩,而且它们支持全文搜索.它们不是事务安全的,而且也不支持外键。如果事物回滚将造成不完全回滚,不具有原子性。如果执行大量的SELECT,MyISAM是更好的选择。

InnoDB:
这种类型是事务安全的.它与BDB类型具有相同的特性,它们还支持外键.InnoDB表格速度很快.具有比BDB还丰富的特性,因此如果需要一个事务安全的存储引擎,建议使用它.如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。对于支持事物的InnoDB类型的标,影响速度的主要原因是AUTOCOMMIT默认设置是打开的,而且程序没有显式调用BEGIN 开始事务,导致每插入一条都自动Commit,严重影响了速度。可以在执行sql前调用begin,多条sql形成一个事物(即使autocommit打开也可以),将大大提高性能。

2)新建JavaBean,不要忘记要有一个无参数的默认构造函数。

package com.seeyon.bean;

/**
 * User实体类
 * 
 * @author Kuang.Hs
 * @version <b>V1.0</b> 2008-4-28 下午06:12:13
 */
public class User {

	private Integer id;// 编号

	private String name;// 姓名

	private Integer age;// 年龄

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public User() {
	}

}

3)新建Hibernate 实体类映射文件,注意主键的生成方式。

<?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.seeyon.bean.User" table="user">
		<id name="id" column="id" type="java.lang.Integer" unsaved-value="null">
			<generator class="native" />
		</id>
		<property name="name" column="name" type="java.lang.String" />
		<property name="age" column="age" type="java.lang.Integer" />
	</class>
</hibernate-mapping>

4)新建Hibernate 的配置文件。

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<!-- Generated by MyEclipse Hibernate Tools.                   -->
<hibernate-configuration>

<session-factory>

	<!-- DB参数 -->
	<property name="connection.username">root</property>
	<property name="connection.url">jdbc:mysql://127.0.0.1/hbnt?useUnicode=true&characterEncoding=utf8</property>
	<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
	<property name="myeclipse.connection.profile">hbnt_mysql</property>
	<property name="connection.password">123456</property>
	<property name="connection.driver_class">
		com.mysql.jdbc.Driver
	</property>
	<property name="hibernate.show_sql">true</property>
	<property name="hibernate.format_sql ">true</property>
	
	<!-- 连接池参数设置 指定使用C3P0,Hibernate默认的连接池有Bug-->
	<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

	<!-- 连接池详细参数 
		<property name="c3p0.min_size">6</property>
		<property name="c3p0.max_size">60</property>
		<property name="c3p0.timeout">1800</property>
		<property name="c3p0.max_statements">80</property> -->

	<!-- 实体类mapping映射 -->
	<mapping resource="com/seeyon/bean/User.hbm.xml" />

</session-factory>

</hibernate-configuration>

 注:

       useUnicode=true&characterEncoding=utf8 是为了强制连接Mysql时使用UTF-8.

4)MyEclipse默认生成的HibernateSessionFactory 也帖一下吧,熟悉的就不用看了,帖出来主要是为了防止没有此文件给大家产生疑惑。

package com.seeyon.hibernate;

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 = "/com/seeyon/hibernate/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) threadLocal.get();

		if (session == null || !session.isOpen()) {
			if (sessionFactory == null) {
				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;
	}

}

 5)简单准备了一个生成随机用户对象的类,供后面调用。这个大家可以随意实现。

package com.seeyon.common;

import java.util.ArrayList;
import java.util.Random;

import com.seeyon.bean.User;

/**
 * 生成常用名字
 * 
 * @author Kuang.Hs
 * @version <b>V1.0</b> 2008-5-12 下午02:30:28
 */
public class UserFactory {
	private static Random random = new Random();

	private static ArrayList<String> surnameCache = new ArrayList<String>();// 姓缓存

	private static int surnameCacheSize = 0; // surnameCache 长度缓存一下

	private static ArrayList<String> secondNameCache = new ArrayList<String>();// 名缓存

	private static int secondNameCacheSize = 0; // secondNameCache 长度缓存一下

	private static String[] commonNamesTop50 = { "张伟", "王伟", "王芳", "李伟", "王秀英",
			"李秀英", "李娜", "张秀莲", "刘伟", "张敏", "张丽", "王静", "王丽", "李强", "张静", "李敏",
			"王敏", "王磊", "李军", "刘洋", "李静", "王勇", "张勇", "王艳", "李杰", "张磊", "王强",
			"王军", "张杰", "李娟", "张艳", "张涛", "王涛", "李明", "李艳", "王超", "李勇", "王娟",
			"刘杰", "王秀兰", "李霞", "刘敏", "张军", "李丽", "张强", "王平", "王刚", "王杰", "李桂英",
			"刘芳" };// 公安部统计全国常见姓名前50名

	private static int MIN_USER_AGE = 20; // 员工最小年龄

	private static int MAX_USER_AGE = 35; // 员工最大年龄

	/**
	 * 随机返回公安部统计全国常见姓名前50的姓名之1
	 * 
	 * @return 全国常见姓名前50之1(随机)
	 */
	public static String getCommonNameInTop50ByRandom() {
		return commonNamesTop50[random.nextInt(commonNamesTop50.length)];
	}

	/**
	 * 根据全国常见前50姓名生成常见的姓名
	 * 
	 * @return
	 */
	public static String getRandomCommonName() {
		if (surnameCache.size() == 0 || secondNameCache.size() == 0) {
			for (int i = 0; i < commonNamesTop50.length; i++) {
				String name = commonNamesTop50[i];
				surnameCache.add(name.substring(0, 1));
				secondNameCache.add(name.substring(1, name.length()));
				Logger.debug(name + "\t" + surnameCache.get(i) + "\t"
						+ secondNameCache.get(i));
			}
			surnameCacheSize = surnameCache.size();
			secondNameCacheSize = secondNameCache.size();
		}
		return surnameCache.get(random.nextInt(surnameCacheSize))
				+ secondNameCache.get(random.nextInt(secondNameCacheSize));
	}

	/**
	 * 根据全国常见前50姓名生成常见的用户
	 * 
	 * @return
	 */
	public static User getRandomCommonNameUser() {
		User user = new User();
		user.setName(getRandomCommonName());
		if (MIN_USER_AGE > MAX_USER_AGE) {
			int temp = MIN_USER_AGE;
			MIN_USER_AGE = MAX_USER_AGE;
			MAX_USER_AGE = temp;
			Logger.error("参数 MIN_USER_AGE 的值不能比 MAX_USER_AGE 大,已纠正。");
		}
		user.setAge(MIN_USER_AGE + random.nextInt(MAX_USER_AGE - MIN_USER_AGE));
		return user;
	}
}

  6)开始吧,写我了一个Hibernate调用类。

package com.seeyon.part11;

import java.util.Date;
import java.util.Scanner;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import com.seeyon.bean.User;
import com.seeyon.common.Log4jInit;
import com.seeyon.common.Logger;
import com.seeyon.common.UserFactory;

/**
 * 主线:Hibernate简单插入数据。
 * <p>
 * 扩展:简单插入size条数据,了解Hibernate性能。
 * 
 * @author Kuang.Hs
 * @version <b>V1.2</b> 2008-4-28 下午06:10:26
 */

public class HibernateDemo1 {
	public static int getInputValue() {

		Scanner sc = new Scanner(System.in);
		int value = 0;
		try {
			value = sc.nextInt();
		} catch (RuntimeException e) {
			Logger.error(e);
			System.out.println("輸入有誤,請重新輸入:");
			return getInputValue();
		}

		return value;
	}

	public static void main(String[] args) {

		new Log4jInit().init();

		System.out.println("請輸入要插入數據的條數:");
		int size = getInputValue();

		Date date_start = new Date();
		Logger.info("插入" + size + "条数据的起始时间:" + date_start);

		// Configuration 负责管理 Hibernate配置信息
		Configuration config = new Configuration()
				.configure("/com/seeyon/hibernate/hibernate.cfg.xml");

		// config 建立 SessionFactory
		// SessionFactory 將用於建立 Session
		SessionFactory sessionFactory = config.buildSessionFactory();

		// 开Session,相当于JDBC的Connection
		Session session = sessionFactory.openSession();
		
		// 打开事务
		Transaction tx = session.beginTransaction();

		// 將对象映射至数据库表格中保存
		for (int i = 0; i < size; i++) {
			// 將持久化的物件
			User user = UserFactory.getRandomCommonNameUser();
			session.save(user);
			if (i % 100 == 0) {
				session.flush();
				session.clear();
			}
		}
		
		tx.commit();
		session.close();
		sessionFactory.close();
		Date date_end = new Date();
		Logger.info("插入" + size + "条数据的结束时间:" + date_end);
		Logger.info("插入" + size + "条数据,共耗时:"
				+ (date_end.getTime() - date_start.getTime()) + "ms");

	}
}

 好啦,到此就全部结束啦,运行一下HibernateDemo1 就有结果啦。还是很简单的吧。Hibernate的难,不是难在Api的学习,而是对ORM思想的理解,和性能的调优配置。

  • 描述: 图一
  • 大小: 21.3 KB
   发表时间:2008-05-18  
觉得比较基础,期待LZ的高级应用和调优的文章
0 请登录后投票
   发表时间:2008-05-18  
小况终于搞 HIBERNATE 了。^_^ 坚持下去。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics