hibernate系列(一)hibernate入门

原创
2015/02/07 10:24
阅读数 225
最近开始学习hibernate,然后就想把这个学习历程总结下来。还是打算主要分两个过程,第一个过程:学会使用hibernate,第二个过程:做一些源码分析,更加深入的理解。

言归正传,开始入门案例,这里的入门案例不牵扯其他框架,所以一开始学习的时候尽量不要牵扯其他框架,如SpringMVC。如果入门时牵涉其他框架,有时候会搞不清楚hibernate和其他框架的责任机制,本工程虽然搭建的是SpringMVC项目,主要是为后来服务,但是目前几乎用不到:
hibernate有两种配置文件,一种就是像jdbc那样连接数据库的配置文件,另一种就是domain类和数据库表之间的映射文件。

第一种配置文件,又有两种形式,可以是properties文件,也可以是xml文件,先来说下xml形式的文件,文件名为hibernate.cfg.xml,可以是其他文件名,如下:

<?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 name="hibernateSessionFactory">
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password">ligang</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.default_schema">hibernate</property>
    </session-factory>
</hibernate-configuration>

前面四个属性和jdbc配置是一样的,后面的hibernate.dialect即选择使用哪种方言,hibernate中有些特性是需要特定的数据库支持的,因此需要明确指定使用哪种方言,不同的数据库甚至相同的数据库不同的版本、不同的引擎,他们都有各自的方言实现,如mysql就有5种形式的方言。目前我还不是特别清楚,所以就暂时使用org.hibernate.dialect.MySQLDialect类,所有的方言都继承了Dialect类,如下所示:


hibernate.show_sql属性为true则是将产生的sql语句显示出来。
properties形式的,文件名是hibernate.properties文件,目前我还没找到是否允许是其他文件名。如下:

hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost:3306/hibernate?useUnicode=true&characterEncoding=utf-8
hibernate.connection.username=root
hibernate.connection.password=ligang
hibernate.show_sql=true

和上面的xml文件没有什么区别。

第二种配置文件,即domain类和数据库表的映射文件,先说domain类,如Customer类,如下:

public class Customer {

	private Long id;
	private String name;
	private String email;
	private Timestamp registeredTime;
        //省略get、set方法
}

对应的映射文件是:Customer.hbm.xml,可以是其他文件名,
<?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.ligang.domain.Customer" table="customer">
		<id name="id" column="id" type="long">
			<generator class="identity"/>
		</id>
		<property name="name" column="name" type="string"/>
		<property name="email" column="email" type="string"/>
		<property name="registeredTime" column="registeredTime" type="timestamp"/>
	</class>
</hibernate-mapping>

其中class标签的name指明了哪个domain类,table指明该domain类所对应的数据库的表。
id标签中的generator 来专门说明主键的生成策略,如可以是increment、identity、sequence、native等。
increment:则是由hibernate自增来生成主键。
identity:则是由底层数据库自增来生成主键,支持的数据库有:DB2、mysql、SqlServer等。
sequence:也是有底层数据库来生成主键,支持的数据库有:DB2、oracle等。
native:根据底层数据库所支持的能力,自动从identity、sequence中挑选一个作为主键的生成策略。

然后就是property标签:name指明Customer的属性,column指明表的列名,type则是java类型和表中字段类型的桥梁。如java中的String类型,如果要映射到数据库中的varchar类型,则需要type为string,如果要映射到数据库中的text类型,则type为text。具体的类型间的映射关系可以到网上搜一搜。

准备工作做完了,然后就要开始使用hibernate了,我的maven工程使用的是4.3.6.Final版本的hibernate,后面提供下载。
hibernate的几个重要概念Configuration、SessionFactory、Session、Transaction、Query和Criteria:
Configuration:用于配置和启动hibernate,然后可以创建出SessionFactory。
SessionFactory:作为产生session的工厂,一个SessionFactory实例代表一个数据库存储源,如果要访问多个数据库,则需要为每个数据库创建一个单独的SessionFactory实例。它是重量级的,内部有很多缓存,不可随意创建和销毁。
Session:用于增删改对象。
Transaction:用于事务的功能。
Query和Criteria:用于查询数据。

首先,我声明了这样的一个接口HibernateDao,用于获取Session,如下:

public interface HibernateDao {

	public Session getSession();
}

它的实现类HibernateDaoImpl如下:
@Repository
public class HibernateDaoImpl implements HibernateDao{
	
	private SessionFactory sessionFactory;

	public HibernateDaoImpl(){
		Configuration config=new Configuration();
		config.addClass(Customer.class);
		sessionFactory=config.buildSessionFactory();
	}

	@Override
	public Session getSession() {
		return sessionFactory.openSession();
	}
}

这里主要是对hibernate指明之前已说明的两种配置文件,一种连接数据库的配置文件,一种domain类对应数据库中表的配置文件。
对于连接数据库的配置文件:如何接收properties形式的配置文件,又如何接收xml形式的配置文件。
(1)接收properties形式的配置文件:对于上述的代码,config.buildSessionFactory()(这是一个过时的方法)会去尝试在类路径的根目录下加载hibernate.properties配置文件。我目前只知道这种形式来接收properties形式的配置文件,路径和文件名都是限制死的,证据如下:

public SessionFactory buildSessionFactory() throws HibernateException {
		Environment.verifyProperties( properties );
		ConfigurationHelper.resolvePlaceHolders( properties );
		final ServiceRegistry serviceRegistry =  new StandardServiceRegistryBuilder()
				.applySettings( properties )
				.build();
		setSessionFactoryObserver(
				new SessionFactoryObserver() {
					@Override
					public void sessionFactoryCreated(SessionFactory factory) {
					}

					@Override
					public void sessionFactoryClosed(SessionFactory factory) {
						( (StandardServiceRegistryImpl) serviceRegistry ).destroy();
					}
				}
		);
		return buildSessionFactory( serviceRegistry );
	}

这里用到了Environment类,所以类加载器要去加载Environment类,并会执行它的静态代码块,如下:



(2)接收xml形式的配置文件:需要使用config.configure(),如下所示:
public HibernateDaoImpl(){
		Configuration config=new Configuration();
		config.configure();
		config.addClass(Customer.class);
		sessionFactory=config.buildSessionFactory();
	}

config.configure()会默认从类路径的根目录下去加载hibernate.cfg.xml配置文件,源代码如下:
public Configuration configure() throws HibernateException {
		configure( "/hibernate.cfg.xml" );
		return this;
}

config.configure()会调用含有参数的configure()方法,所以如果我们想在类路径下的子目录中去放置我们的配置文件,则需要使用含参数的configure(相对类路径的路径)。并且文件名可以随意指定,如我们的配置文件可以放到类路径下/hibernate/config/文件夹中,我可以这样配置config.configure("/hibernate/config/hibernate.cfg.xml")。

对于domain类和数据库表之间的映射文件的加载,可以使用config.addClass(Customer.class),该方法会去domain所在路径下寻找Customer.hbm.xml映射文件,源代码如下:

public Configuration addClass(Class persistentClass) throws MappingException {
		String mappingResourceName = persistentClass.getName().replace( '.', '/' ) + ".hbm.xml";
		LOG.readingMappingsFromResource( mappingResourceName );
		return addResource( mappingResourceName, persistentClass.getClassLoader() );
	}

persistentClass.getName()得到类的完整名称,对于本工程来说是com.ligang.domain.Customer,最终得到的mappingResourceName 为com/ligang/domain/Customer.hbm.xml。
如果该映射文件不像放到domain类的同一个目录下,想放到类路径下的hibernate/mapping/文件夹下则可以使用config.addResource("hibernate/mapping/Customer.hbm.xml"),这里路径的前面不能含有/,文件名可以随意取,没有要求。

加载配置文件说完了,然后继续下面的步骤,开始创建SessionFactory了。

sessionFactory=config.buildSessionFactory();

对于上述方法,已是过时的方法,推荐的方法是buildSessionFactory(serviceRegistry),网上有很多的说法是,使用如下代码替代:
ServiceRegistry serviceRegistry=new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();

但是目前对于4.3.6.Final的hibernate来说ServiceRegistryBuilder已经过时,替换类则是StandardServiceRegistryBuilder,可以使用如下方案:
ServiceRegistry serviceRegistry=new StandardServiceRegistryBuilder().applySettings(config.getProperties()).build();
sessionFactory=config.buildSessionFactory(serviceRegistry);

我们再看下config.buildSessionFactory()的源码:
public SessionFactory buildSessionFactory() throws HibernateException {
		Environment.verifyProperties( properties );
		ConfigurationHelper.resolvePlaceHolders( properties );
		final ServiceRegistry serviceRegistry =  new StandardServiceRegistryBuilder()
				.applySettings( properties )
				.build();
		setSessionFactoryObserver(
				new SessionFactoryObserver() {
					@Override
					public void sessionFactoryCreated(SessionFactory factory) {
					}

					@Override
					public void sessionFactoryClosed(SessionFactory factory) {
						( (StandardServiceRegistryImpl) serviceRegistry ).destroy();
					}
				}
		);
		return buildSessionFactory( serviceRegistry );
	}

它内部也是使用了StandardServiceRegistryBuilder,所以说上述方案还没config.buildSessionFactory()这个过时的方案好。对于ServiceRegistry这一块,日后再详细研究,至少我感觉hibernate这一块设计的不是很好。我理解的好的设计,对于用户来说是简单易用的,尽量对外不要暴漏内部的一些机制,而这里ServiceRegistry则会让一个初学者一头雾水,需要花费更多的时间去理解内部的机制。

有了SessionFactory,我们便可以获取Session,然后进行增删改查了,建立了如下的单元测试类如下:

@RunWith(JUnit4ClassRunner.class)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/mvc-servlet.xml")
public class CustomerDaoTest {
	
	@Autowired
	private HibernateDao hibernateDao;
	
	@Test
	public void testAdd(){
		Customer customer=new Customer();
		customer.setName("小明");
		customer.setEmail("123456789@qq.com");
		Timestamp t=new Timestamp(System.currentTimeMillis());
		customer.setRegisteredTime(t);
		Session session=hibernateDao.getSession();
		Transaction tx=session.beginTransaction();
		session.save(customer);
		tx.commit();
		session.close();
	}
}

运行单元测试方法,便可以看到成功的进行了增添操作。

若想转载请注明出处
作者:乒乓狂魔
展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部