Hibernate学习笔记
Hibernate就是对数据库进行封装,使得程序员可以直接操作对象而不用写具体的数据库操作。
ORM(Object Relation Mapping,对象关系映射)的作用是在关系型数据库和对象之间做了一个映射。从对象(Object)映射到关系(Relation),再从关系映射到对象。这样,我们在操作数据库的时候,不需要再去和复杂SQL打交道,只要像操作对象一样操作它就可以了(把关系数据库的字段在内存中映射成对象的属性)。
Hibernate是一个开放源代码的ORM框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的ORM框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
Hibernate的核心:
从上图中,我们可以看出Hibernate六大核心接口,两个主要配置文件,以及他们直接的关系。Hibernate的所有内容都在这了。那我们从上到下简单的认识一下,每个接口进行一句话总结。
1、Configuration接口:负责配置并启动Hibernate
2、SessionFactory接口:负责初始化Hibernate
3、Session接口:负责持久化对象的CRUD操作
4、Transaction接口:负责事务
5、Query接口和Criteria接口:负责执行各种数据库查询
注意:Configuration实例是一个启动期间的对象,一旦SessionFactory创建完成它就被丢弃了。
《Hibernate初探之单表映射》
首先建一个hibernate.cfg.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="connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 连接数据库名称 设置字符格式防止中文乱码 --> <property name="connection.url">jdbc:mysql://localhost:3306/hibernate?useUnicode=true&characterEncoding=UTF-8</property> <!-- /// 表示本地数据库 下面语句同上面一条 --> <property name="connection.url">jdbc:mysql:///hibernate?useUnicode=true&characterEncoding=UTF-8</property> <!-- 用户名 --> <property name="connection.username">root</property> <!-- 密码 --> <property name="connection.password">123456</property> <!-- 指定对应数据库的方言,hibernate为了更好适配各种关系数据库,针对每种数据库都指定了一个方言dialect --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <!-- sql语句输出到控制台 --> <property name="show_sql">true</property> <!-- 输出到控制台的sql语句进行排版 --> <property name="format_sql">true</property> <!-- create:删除以前的创建新的 update:原有的基础上更新 --> <property name="hbm2ddl.auto">create</property> <!-- 映射文件 --> <mapping resource="Students.hbm.xml"/> </session-factory> </hibernate-configuration>
写一个学生类
实体类和数据库中的表相对应
import java.util.Date; public class Students { private int sid; private String sname; private String gender; private Date birthday; private String address; public Students() { } public Students(int sid, String sname, String gender, Date birthday, String address) { super(); this.sid = sid; this.sname = sname; this.gender = gender; this.birthday = birthday; this.address = address; } public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "Students [sid=" + sid + ", sname=" + sname + ", gender=" + gender + ", birthday=" + birthday + ", address=" + address + "]"; } }
创建对象-关系映射配置文件,后缀是.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 2017-1-29 20:54:05 by Hibernate Tools 3.5.0.Final --> <hibernate-mapping> <!-- 映射的类和表 --> <class name="Students" table="STUDENTS"> <!-- 被id标签括起来表示主键 name类中名称 type数据类型:Java的数据类型或者Hibernate的数据类型 --> <id name="sid" type="int"> <column name="SID" /> <!-- 主键生成策略 native根据底层数据库自动生成,例如MySQL就是auto_increment assigned手工赋值 --> <generator class="native" /> </id> <property name="sname" type="java.lang.String"> <column name="SNAME" /> </property> <property name="gender" type="java.lang.String"> <column name="GENDER" /> </property> <property name="birthday" type="java.util.Date"> <column name="BIRTHDAY" /> </property> <property name="address" type="java.lang.String"> <column name="ADDRESS" /> </property> </class> </hibernate-mapping>
使用 junit 测试:
@Test 测试注释标签 测试方法
@Before 初始化方法 执行测试方法之前会执行这个方法
@After 释放资源 执行测试方法之后会执行这个方法
import java.sql.Connection; import java.sql.SQLException; import java.util.Date; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.jdbc.Work; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; public class StudentsTest { private SessionFactory sessionFactory; private Session session; private Transaction transaction; @Before public void init() { // 创建配置对象 Configuration config = new Configuration().configure(); // 创建服务注册对象 ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry(); // 创建会话工厂对象 sessionFactory = config.buildSessionFactory(serviceRegistry); // 创建会话对象 session = sessionFactory.openSession(); // session = sessionFactory.getCurrentSession(); // 开启事务 transaction = session.beginTransaction(); } @After public void destroy() { transaction.commit(); // 提交事务 session.close(); // 关闭会话 sessionFactory.close(); // 关闭会话工厂 } @Test public void testSaveStudents() { Students s = new Students(1, "段文弱", "男", new Date(), "天朝"); session.save(s); } }
Hibernate执行流程
session是一个操纵数据库对象,session与connection是多对一的关系。
session默认事务不是自动提交。需要Transaction提交。transaction.commit();
可以通过设置doWork()变成自动提交(不推荐)
session.doWork(new Work(){ @Override public void execute(Connection connection) throws SQLException { connection.setAutoCommit(true); } });
获得session:
1.openSession 每次都获得一个新的session,需要手动关闭
2.getCurrentSession 使用现有的session对象,需要在hibernate.cfg.xml中配置
<property name="hibernate.current_session_context_class">thread</property>
在事务提交或者回滚之后会自动关闭,(所以啊……不需要关闭……会有错误!错了好多次才反应过来!
基本数据类型:
时间类型:
对象类型
1.clob和text对应大文本文件,blob对应大的二进制文件,例如视频音频图片
2.java中的clob对应存储大文本文件,java中的blob对应存储大二进制文件
MySQL不支持标准SQL的CLOB类型,在Mysql中,用TEXT,MEDIUMTEXT及LONGTEXT类型来表示长度超过255的长文本数据
@Test public void testWriteBlob() throws IOException { Students s = new Students(100, "段文弱", "男", new Date(), "天朝"); File file = new File("E:"+File.separator+"图片"+File.separator+"bobo.jpg"); // 获得照片文件的输入流 InputStream input = new FileInputStream(file); // 创建一个Blob对象 Blob image = Hibernate.getLobCreator(session).createBlob(input, input.available()); // 设置照片属性 s.setPicture(image); session.save(s); } @Test public void testReadBlob() throws Exception { Students s = (Students)session.get(Students.class, 1); Blob image = s.getPicture(); InputStream input = image.getBinaryStream(); File file = new File("E:"+File.separator+"bobo.jpg"); OutputStream output = new FileOutputStream(file); // 创建缓冲区 byte[] buffer = new byte[input.available()]; //System.out.println(input.available()); input.read(buffer); output.write(buffer); input.close(); output.close(); }
组件属性:某个属性是用户自定义的对象
<component name="取的名字" class="类名"> <property name="类中属性" column="对应生成数据库中列属性名"> </component>
会在数据库中将自定义类中的属性也当做一个字段。
增删改查:
Students s = new Students(); //增加数据 session.save(s); // 获取 Object get/load(Class, 主键) Students s = (Students)session.get(Students.class, 1); Students s = (Students)session.load(Students.class, 1); // 修改 session.update(s); // 删除 session.delete(s);
get load区别:
1.get调用后立即发出sql语句,并返回对象。load调用后返回代理对象,保存了实体对象id,直到使用了对象的非主键属性时才发出sql语句
2.当查询到数据为空时,get返回null,load返回objectNotFound异常