hibernate系列(一)hibernate入门

[size=medium]最近开始学习hibernate,然后就想把这个学习历程总结下来。还是打算主要分两个过程,第一个过程:学会使用hibernate,第二个过程:做一些源码分析,更加深入的理解。

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

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

<?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>

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

[img]http://dl2.iteye.com/upload/attachment/0101/7165/302252fa-3336-3f95-87ec-b2557202447f.png[/img]
[size=medium]hibernate.show_sql属性为true则是将产生的sql语句显示出来。
properties形式的,文件名是hibernate.properties文件,目前我还没找到是否允许是其他文件名。如下:[/size]

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

[size=medium]和上面的xml文件没有什么区别。

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

public class Customer {

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

[size=medium]对应的映射文件是:Customer.hbm.xml,可以是其他文件名,[/size]

<?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>

[size=medium]其中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,如下:[/size]

public interface HibernateDao {

public Session getSession();
}

[size=medium]它的实现类HibernateDaoImpl如下:[/size]

@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();
}
}

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

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 );
}

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

[img]http://dl2.iteye.com/upload/attachment/0101/7171/df2ee673-d8dc-3501-aabc-34d7218f1a07.png[/img]

[size=medium](2)接收xml形式的配置文件:需要使用config.configure(),如下所示:[/size]

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

[size=medium]config.configure()会默认从类路径的根目录下去加载hibernate.cfg.xml配置文件,源代码如下:[/size]

public Configuration configure() throws HibernateException {
configure( "/hibernate.cfg.xml" );
return this;
}

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

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

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

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

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

sessionFactory=config.buildSessionFactory();

[size=medium]对于上述方法,已是过时的方法,推荐的方法是buildSessionFactory(serviceRegistry),网上有很多的说法是,使用如下代码替代:[/size]

ServiceRegistry serviceRegistry=new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();

[size=medium]但是目前对于4.3.6.Final的hibernate来说ServiceRegistryBuilder已经过时,替换类则是StandardServiceRegistryBuilder,可以使用如下方案:[/size]

ServiceRegistry serviceRegistry=new StandardServiceRegistryBuilder().applySettings(config.getProperties()).build();
sessionFactory=config.buildSessionFactory(serviceRegistry);

[size=medium]我们再看下config.buildSessionFactory()的源码:[/size]

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 );
}

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

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

@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();
}
}

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

若想转载请注明出处: [url]http://lgbolgger.iteye.com/blog/2124793[/url]
作者:iteye的乒乓狂魔
[/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值