重学hibernate,决定分享学习笔记。
新建一个project,名字叫做hibernate, 普通的java project就可以了。导入jar包,hibernate依赖很多jar包,我把用上的jar包都列出来,包括但不限于这些。这些jar包作什么用我就不一一解释了。因为我用到了sqlserver 2000,所以数据库驱动msbase.jar, mssqlserver.jar, msutil.jar要copy进来,如果用其他的数据库, 则这个要替换掉,还有一个我比较奇怪的是,Hibernate依赖了jta.jar. 这些jar包到处都有,如果你想集中download,到hibernate.org下载最新的全包hibernate-distribution-3.3.2.GA。
在src目录下新建包dao,里面放所有的dao接口;新建package dao.hibernate放dao接口的hibernate实现类,sessionfactory,
Hibernate.cfg.xml. 新建package model放所有的pojo以及hbm映射文件。最后src目录是这个样子的:
在dao.hibernate建HibernateSessionFactory.java:
package dao.hibernate; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.cfg.Configuration; public class HibernateSessionFactory { private static String CONFIG_FILE_LOCATION = "/dao/hibernate/Hibernate.cfg.xml"; private static final ThreadLocal threadLocal = new ThreadLocal(); private static final Configuration cfg = new Configuration(); private static org.hibernate.SessionFactory sessionFactory; public static Session currentSession() throws HibernateException { Session session = (Session) threadLocal.get(); if (session == null || !session.isOpen()) { if (sessionFactory == null) { try { cfg.configure(CONFIG_FILE_LOCATION); sessionFactory = cfg.buildSessionFactory(); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } } session = (sessionFactory != null) ? sessionFactory.openSession() : null; threadLocal.set(session); } return session; } public static void closeSession() throws HibernateException { Session session = (Session) threadLocal.get(); threadLocal.set(null); if (session != null) { session.close(); } } private HibernateSessionFactory() { } }
在dao.hibernate下建Hibernate.cfg.xml: 需要注意的是如果是sqlserver2005,则驱动名称有所不同:com.microsoft.sqlserver.jdbc.SQLServerDriver,这个问题很贱。
<?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"> <hibernate-configuration> <session-factory> <property name="dialect">org.hibernate.dialect.SQLServerDialect</property> <!-- jdbc --> <property name="connection.url">jdbc:sqlserver://localhost:2431;DatabaseName=hibernate</property> <property name="connection.driver_class">com.microsoft.jdbc.sqlserver.SQLServerDriver</property> <property name="connection.username">sa</property> <property name="connection.password">123456</property> <property name="jdbc.fetch_size">50</property> <property name="jdbc.batch_size">30</property> <property name="show_sql">true</property> <property name="format_sql">false</property> <property name="connection.autocommit">true</property> <property name="current_session_context_class">thread</property> <mapping resource="model/Book.hbm.xml"/> </session-factory> </hibernate-configuration>
一个BaseHibernateDao:
package dao.hibernate; import org.hibernate.Session; public class BaseHibernateDao { //该类很简单,就是从HibernateSessionFactory返回当前线程的Session public Session getSession() { return HibernateSessionFactory.currentSession(); } }
新建pojo Book.java:
public class Book { private String id; private String name; private String author; private float price; public Book(){}; public Book(String id, String name, String author, float price){ this.id = id; this.name = name; this.author = author; this.price = price; } //带上toString,方便测试. public String toString(){ return "{id:" + id + "/nname:" + name + "/nauthor:" + author + "/nprice:" + price + "}"; } // getter and setter ignored }
你需要一个数据库来做测试,不管怎么样,学hibernate数据库肯定是要用到的。我在家里用的是sqlserver2000,我新建的数据库名字就叫作hibernate。
在model下新建一个映射文件Book.hbm.xml:值得注意的是:如果数据库有schema,别忘了加上schema和catalog(数据库名)
该文件后面带有DML建表语句.
<?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 package="model"> <class name="Book" table="book" schema="dbo" catalog="hibernate"> <id name="id" column="id"> <generator class="uuid" /> </id> <property name="name" /> <property name="author" /> <property name="price" /> </class> </hibernate-mapping> <!-- create table book ( id int identity(1,1) primary key, name varchar(20) not null, author varchar(20), price float ) -->
一个BookHibernateDao.java:是BookDao的实现类. 值得注意的是该类里面带有test case.
package dao.hibernate; import java.util.List; import org.hibernate.Transaction; import model.Book; import dao.BookDao; public class BookHibernateDao extends BaseHibernateDao implements BookDao{ public List<Book> list() { return getSession().createQuery("from Book").list(); } public Book findById(String id) { return (Book) getSession().get(Book.class, id); } public void save(Book book) { //Transaction tx = getSession().beginTransaction(); getSession().saveOrUpdate(book); getSession().flush(); //tx.commit(); } public void delete(String id) { Book b = (Book) getSession().load(Book.class, id); //Transaction tx = getSession().beginTransaction(); getSession().delete(b); //tx.commit(); } //test case public static void main(String[] args){ BookDao dao = new BookHibernateDao(); List<Book> list = dao.list(); System.out.println(list.size()); for(Book b : list){ System.out.println(b); } Book b = new Book(null, "book name", "book author", 11.5F); dao.save(b); } }
运行BookHibernateDao就可以测试hibernate是否可以正常运行了.如果不出错,应该打印出所有的book.
这里解释几个问题:
1 HibernateSessionFactory的这种写法是MyEclipse自动生成的代码, 如果你手头也有MyEclipse,你也可以自动生成HibernateSessionFactory, Hibernate.cfg.xml, pojo, hbm.xml 以及dao, 但是我觉得最好都动手写一下, 包括配置文件.要不出去面试的时候人家问某某属性该怎么配? 咦? 没听过~? 我个人觉得HibernateSessionFactory这种写法很好,它是采用ThreadLocal,把session和当前线程关联,解决了session的线程安全问题。
2 BookHibernateDao中save和delete方法中我把transaction的东西注销了,这得益于Hibernate.cfg.xml中的配置:
<property name="connection.autocommit">true</property> , 这句话的意思相当于在jdbc中:connection.setAutoCommit(true);如果你没有配置connection.autocommit = true; 就需要在程序中显式的提交事务;这个问题不少新手问到过。但是就算配置了autocommit, 也不要忘记了getSession().flush(); 为什么要调这句话,源码中是这么说的:Force this session to flush. Must be called at the end of a unit of work, before commiting the transaction and closing the session; session对对象的增删改都是暂时做标记放在session里面,调用flush之后,session会和数据库同步,该存的存,该删的删.
3 关于id: 在hibernate的世界里, 识别一个对象靠id,本例中使用uuid来自动生成32位的String类型的id,uuid的灵活性好,不依赖于数据库,但是有点浪费空间; 也可以换成int型的id,
create table book (
id int identity(1,1) primary key,
name varchar(20) not null,
author varchar(20),
price float
)
则可以使用identity 或者native 生成器, <generator class="identity" /> ; 如果是oracle数据库而且使用sequence作id生成器,则可以选sequence , <generator class="sequence"> <param name="sequence">sequence 的名字 </param> </generator> 。