Hibernate,对于java来说很重要的一个东西,用于持久层。之前看了很多配置的,都不行,自己来写一个配置成功的。
环境:jdk1.8,eclipse-jee-oxygen,mysql-connector-java-5.1.46,hibernate 5.2.
首先要确保你的jdk,eclipse和mysql装好。然后下载jar包,mysql和hibernate的jar包。
然后安装JBoss插件,eclipse中Help-----eclipse market里面输入JBoss并搜索,找到JBoss之后,install,这里只需要对应hibernate的那些即可。
Confirm之后,accept,安装即可。
先简单叙述一下开发流程,后面有详细地说明每一步在干什么以及为什么要这么做。
1.准备开发环境,数据库中创建数据库及表。
2.创建持久化类
3.设计映射文件,也就是利用hibernate讲POJO映射到数据库。
4.创建hibernate配置文件Hibernate.cfg.xml。
5.编写辅助工具HibernateUtil类,用来实现对Hibernate的初始化并提供获得Session的方法,这一步是我们这次需要的,具体要看你的项目是否需要。
6.编写DAO层。
7.编写Service层。
8.编写测试类,并用Junit测试。
先上一张完整的目录:
1.创建项目
创建Dynamic Web Project项目,命名为MyHibernate,在项目上右键,New---Other,在里面找Hibernate,选择Hibernate Configuration File(cfg.xml)。
点击Next按钮,在弹出的对话框中选择配置文件保存的目录,一般默认在src目录,同时需要输入配置文件的名称,一般默认为hibernate.cfg.xml即可。继续Next,在弹出的对话框中填写数据库方言(Database dialect)、数据库驱动(Driver class)、数据库URL、用户名、密码等。MySQL数据库的配置如下:
单击Finish,配置文件就创建成功了,后面有需要可以继续编辑该文件。
2.创建数据库及表。
在MySQL中创建一个名为mysqldb的数据库,在该数据库中创建一张名为USER的表。创建USER表的语句如下:
create table user( id int(11), name varchar(20), password varchar(12), type varchar(6), primary key(id));
3.编写POJO映射类User.java
package org.hibernate.entity; public class User { private int id;//持久化类的标识属性,映射到数据表中的主键列 private String name; private String password; private String type; public User() { // TODO Auto-generated constructor stub } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getType() { return type; } public void setType(String type) { this.type = type; } }
4.编写映射文件User.hbm.xml
这一步可以通过设置直接生成。右键org.hibernate.entity包,new----other,找到hibernate,选择生成hbm.xml。这里只选择自己需要的POJO类生成hbm.xml。
生成之后的内容:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2018-3-16 9:16:18 by Hibernate Tools 3.5.0.Final --> <hibernate-mapping> <class name="org.hibernate.entity.User" table="USER"> <id name="id" type="int"> <column name="ID" /> <generator class="assigned" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> <property name="password" type="java.lang.String"> <column name="PASSWORD" /> </property> <property name="type" type="java.lang.String"> <column name="TYPE" /> </property> </class> </hibernate-mapping>
5.编写hibernate.cfg.xml文件
刚才新建了一个xml文件,里面有一些配置,现在需要增加一些内容。更改之后的内容:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.password">314159</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mysqldb</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 在控制台输出运行时生成的SQL语句,方便调试 --> <property name="show_sql">true</property> <!-- 连接池大小 --> <property name="connection.pool_size">1</property> <!-- 列出所有映射文件 --> <mapping resource="org/hibernate/entity/User.hbm.xml" /> </session-factory> </hibernate-configuration>
6.编写辅助工具类HibernateUtil.java
package org.hibernate.entity; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; public class HibernateUtil { private static SessionFactory sessionFactory; // 创建线程局部变量threadLocal,用来保存Hibernate的Session private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>(); // 使用静态代码块初始化Hibernate static { try { // 读取配置文件方式1,hibernate4.3之前 // Configuration cfg = new Configuration().configure(); // // 创建服务注册对象 // StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() // .applySettings(cfg.getProperties()).build(); // // 创建会话工厂对象SessionFactory // sessionFactory = cfg.buildSessionFactory(serviceRegistry); // // 读取配置文件方式2,hibernate4.3之后 ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure("/hibernate.cfg.xml").build(); //创建会话工厂对象 sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory(); } catch (Throwable ex) { throw new ExceptionInInitializerError(ex); } } // 获得SessionFactory的实例 public static SessionFactory getsSessionFactory() { return sessionFactory; } // 获得ThreadLocal对象管理的Session public static Session getsSession() throws HibernateException { Session session = (Session) threadLocal.get(); if (session == null || !session.isOpen()) { if (sessionFactory == null) { rebuildSessionFactory(); } // 通过SessionFactory对象创建Session对象 session = (sessionFactory != null) ? sessionFactory.openSession() : null; // 将Session对象保存到线程局部变量threadLocal中 threadLocal.set(session); } return session; } // 关闭Session实例 public static void closeSession() { // 从线程局部变量threadLocal中获取之前存入的Session实例 Session session = (Session) threadLocal.get(); threadLocal.set(null); if (session != null) { session.close(); } } // 重建SessionFactory public static void rebuildSessionFactory() { Configuration configuration = new Configuration(); configuration.configure("/hibernate.cfg.xml"); StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(configuration.getProperties()).build(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); } // 关闭缓存和连接池 public static void shutdown() { getsSessionFactory().close(); } }
这里面有一个地方要注意,就是上面的红色注释,创建SessionFactory的方式因为hibernate版本有点不一样,如果选择了不适合的版本,在后面Junit测试的时候,会报“org.hibernate.MappingException: Unknown entity:XXXXXXXXXXXXXXX"的错。
7.编写DAO层接口UserDAO.java
package org.hibernate.dao; import java.util.List; import org.hibernate.entity.User; public interface UserDAO { public void save(User user); public User findByIdGet(int id); public User findByIdLoad(int id); public List<User> findByHQL(String hql); public void delete(User user); public void update(User user); }
8.编写DAO层实现类UserDAOImpl
package org.hibernate.dao; import java.util.ArrayList; import java.util.List; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.entity.HibernateUtil; import org.hibernate.entity.User; public class UserDAOImpl implements UserDAO { // 添加用户,需要事务管理 @Override public void save(User user) { // 创建Session实例 Session session = HibernateUtil.getsSession(); // 创建Transaction实例 Transaction tx = session.beginTransaction(); try { // 使用Session的save方法将持久化对象保存到数据库 session.save(user); // 提交事务 tx.commit(); } catch (Exception e) { e.printStackTrace(); // 出现异常,回滚事务 tx.rollback(); } finally { // 关闭Session连接 HibernateUtil.closeSession(); } } // 根据id查找用户 ,可以不需要事务管理 Get方式 @Override public User findByIdGet(int id) { User user = null; Session session = HibernateUtil.getsSession(); // 使用session的get方法获取指定id的用户 user = (User) session.get(User.class, id); if (user == null || "".equals(user)) { System.out.println("查询id为:" + id + "无结果...."); } session.close(); return user; } // 根据id查找用户 ,可以不需要事务管理 Load方式 @Override public User findByIdLoad(int id) { User user = null; Session session = HibernateUtil.getsSession(); // 使用session的方法获取指定id的用户 user = (User) session.load(User.class, id); if (user == null || "".equals(user)) { System.out.println("查询id为:" + id + "无结果...."); } session.close(); return user; } // 根据HQl语句查询 @Override public List<User> findByHQL(String hql) { List<User> list = new ArrayList<>(); Session session = HibernateUtil.getsSession(); list = session.createQuery(hql).list(); session.close(); return list; } // 删除用户 ,需要事务管理 @Override public void delete(User user) { Session session = HibernateUtil.getsSession(); Transaction tx = session.beginTransaction(); try { session.delete(user); tx.commit(); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(); } } // 修改用户 @Override public void update(User user) { Session session = HibernateUtil.getsSession(); Transaction tx = session.beginTransaction(); try { session.update(user); tx.commit(); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(); } } }
到这里整个Hibernate项目就完成了,下面需要的是测试。
9.编写测试类UserTest.java
这里用Junit测试,如果没有导入Junit的要先导入。在HibernateDemo项目名称上右击,选择Properties,在弹出的窗口左侧选择Java Build Path选项,然后在右侧界面中选择Libraries标签,点击Add Library按钮,在弹出的窗口中选择Junit,如下图所示。
然后点击Next,在version一栏选择Junit 4,然后点击Finish。这样Junit包就引入到项目中了。
接下来在项目中新建org.hibernate.test包,在包名上右击,依次选择New->Junit Test Case菜单,在弹出的窗口中填写测试类的名称和需要测试的类的名称(这个需要填写完整包名),如下图所示:
点击Next按钮,可以选择需要测试的方法,根据需要选择即可。
这时候会生成一个UserTest类,里面包含的是一些空方法,我们要测哪些就给哪些加上方法体。
例如重写testSave,下面是重写之后的类:
package org.hibernate.test; import static org.junit.Assert.*; import org.hibernate.dao.UserDAO; import org.hibernate.dao.UserDAOImpl; import org.hibernate.entity.User; import org.junit.Test; public class UserTest { @Test public void testSave() { UserDAO userDAO=new UserDAOImpl(); try{ User u=new User(); // 设置User对象的各个属性 u.setId(20); u.setName("zhangsan"); u.setPassword("123456"); u.setType("admin"); // 使用UserDAOImpl的save方法将User对象存入到数据库 userDAO.save(u); }catch(Exception e){ e.printStackTrace(); } } @Test public void testFindByIdGet() { fail("Not yet implemented"); } @Test public void testFindByIdLoad() { fail("Not yet implemented"); } @Test public void testFindByHQL() { fail("Not yet implemented"); } @Test public void testDelete() { fail("Not yet implemented"); } @Test public void testUpdate() { fail("Not yet implemented"); } }
接下来在UserTest.java文件名称上右击,依次选择Run As ->Junit Test菜单。再查看数据库中就会发现多了一条记录。
这里可能有报错,像上面说的
1.“org.hibernate.MappingException: Unknown entity:XXXXXXXXXXXXXXX”这个是因为SessionFactory获取的方式不对,因为hibernate的版本问题,根据上面对应的红色注释改一下就好了。
2.ERROR: Field 'id' doesn't have a default value。这个是因为字段的问题,自动生成的User.hbm.xml可能不太一样。
<id name="id" type="int"> <column name="ID" /> <generator class="assigned" /> </id>
这里的generator对应的是数据库中的id字段是否自动增长,assigned就是我写进去20就是20,如果有的自动生成了native,表示的是从1开始自增,如果数据库中没有相应的设定的话可能会报错,所以这里注意一下。
参照原文地址:http://blog.csdn.net/fxdaniel/article/details/42420779
到这里整个项目的创建到测试都完成了,现在来说一下我对每个步骤在干什么和为什么要这么做的理解。
1.创建项目。这里由于使用了JBoss,所以简化了很多。hibernate.cfg.xml是hibernate中非常重要的一个xml文件,里面是一些hibernate的配置,其中session-factory最重要。试想一下我们以前用JDBC连接数据库时候的操作,加载驱动、url、用户名、密码等等,这里也是一样,你既然要操作数据库,最根本的就是连接数据库,所以hibernate的根就是在这个xml中,这里面让jvm知道用的驱动、url、用户名、密码、以及数据库方言(也就是数据库种类mysql啊还是oracle还是sqlserver啊)。hibernate简化了jdbc中一系列操作,直接通过xml配置文件来配置这些信息。
2.编写POJO类(持久化类)。首先要明确hibernate是服务于持久层,什么是持久层,持久层就是存储数据的,在一个项目中,数据要持久地保存。操作数据库实际上是在操作我们面向的对象也就是POJO类,比如我们有一堆桌子,面向对象设计这个桌子,桌子的重量啊,形状啊等信息会被看作是桌子的属性,而数据库里存的也是这些东西。
3.生成映射文件User.hbm.xml。数据库和我们的类(也就是POJO类)是对应的,但是即使我们知道对应,jvm不知道啊,怎么让他知道,用mapping来匹配。一个POJO类对应一个table,既然对应了,那POJO里面的属性和table的字段肯定也是要对应的,因为属性和字段表示的都是桌子的实际性质。所以映射文件的配置,就是让jvm知道那个POJO类对应哪个table。所以看看这个xml里面的配置,是不是和数据库中的字段配置很相似。
4.编写hibernate.cfg.xml文件。一开始生成了一个xml文件,但是这个xml只是在有数据库的时候生成的,但是我们要具体操作哪一个表的时候,xml就不知道了。现在我们的目的是添加一个user进入,那也就是说我们要操作user类,user类对应数据库里的user表,但是jvm现在只知道要操作mysql数据库,而上一步里面,我们让jvm知道了user类和user表是对应的,可是user表在哪个数据库里面存着呢?mysql还是oracle?mysql下的db还是oracle下的db?很自然的,现在只需要让jvm把mysql数据库和mapping对应起来,而这个mapping就是user类和user表的映射。现在整个逻辑通了,操作user类---映射到mysql数据库--映射到user表。
5.编写辅助工具类。刚才我们说的那些东西,都是保存在hibernate.cfg.xml下面,而那下面的标签是<session-factory>,这个SessionFactory是很重要也很重的一个东西,既然刚才说的东西都保存在这里面,我们用的时候肯定也都是从这里面取,所以这个辅助工具类的就是为了取处这个SessionFactory。
6.编写DAO层接口。在三层视图层、业务层、持久层的逻辑中,DAO也就是database access object,直接面向数据库。成熟的编程方式是先写接口,再写实现类。所以DAO层接口和实现分开。
7.DAO层实现类。这个就是利用取出的SessionFactory,再取出SessionFactory中我们需要的元素,操作这些元素也就是直接面向了数据库,通过这个实现类来完成我们的目的。
8.一个Junit测试类。没啥说的,测试项目。
希望通过这个配置来理解简单的hibernate原理。