Hibernate
今天我们来学习hibernate,当我们想把一个数据存在数据库里,首先要在客户端(Client)new 出一个对象(假设为Student),
我们需要连接数据库,使用JDBC来对Student进行操作。
这里要注意的是,在面向对象编程中,我们使用的sql语句并不是面向对象的语言。
而采用hibernate我们就不必使用JDBC了,我们的Student对象直接和hibernate打交道(而不需要再写sql语句).
相关类关系如下图所示,先简单做一个了解:
资源准备
很多公司喜欢使用Annotation开发,所以我们的学习风格依然是重Annotation轻xml配置文件。
准备阶段我们需要下载三个hibernate资源包。
除此之外,我们还需要配合两个文件学习。
第一个是在:hibernate-distribution-3.6.10.Final\documentation\manual\zh-CN\html_single\index.html
这个文件我们是我们学习hibernate的参考文档(简称为文件1)
第二个是:hibernate-search-5.8.0.Final\docs\reference\zh-CN\html_single\index.html
这个文件是我们学习hibernate-annotation的参考文档(简称为文件2)
第一个hibernate程序:HelloWorld
新建一个简单的java项目,名为: Hibernate_0100_HelloWorld
如果我们需要导入多个jar包(同一系列),我们可以:
window–>java–>build path–>user libraries
也就是用户自定义的jar包集合。
以hibernate为例,点击new–>定义名称为hibernate–>add jars(添加自定义的jar包)
–>依次导入:hibernate3.jar, hibernate-distribution\lib\required中的所有包,slf4j-nop-1.6.jar
接着如下图所示,我们点击项目Hibernate_0100_HelloWorld,右键bulid path–>user libraries–>UserLibrary–>hibernate 选中确定即可
我们需要跟数据库建立联系,所以还需要再导入一个jar包:mysql-connector-java-3.1.13-bin.jar以便在mysql中建立对应的表。
1)打开mysql,创建数据库hibernate.
2)建立对应的表
3)在Hibernate_0100_HelloWorld中创建Student.java
例1:
package com.hibernate.model;
public class Student {
private int id;
private String name;
private int age;
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
4)创建测试类StudenTest
例2:
package com.hibernate.test;
public class StudentTest {
public static void main(String[] args) {
}
}
5)在文件1中找到如下代码,创建配置文件:hibernate.cfg.xml(文件名约定俗成,尽量不要更改),并粘贴。
例3:
<?xml version='1.0' encoding='utf-8'?><session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>
</session-factory>
6)修改hibernate.cfg.xml <?xml version='1.0' encoding='utf-8'?>
<session-factory>
<!-- Database connection settings 数据库连接配置 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/hibernate</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- 不常用: JDBC connection pool (use the built-in) -->
<!-- <property name="connection.pool_size">1</property>-->
<!-- SQL dialect (方言 修改为 MySQLDialect)-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 暂时不用:Enable Hibernate's automatic session context management -->
<!-- <property name="current_session_context_class">thread</property>-->
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup
hbm:hibernate mapper
ddl:Data Definition Language 也就是建表语句
这句话决定hibernate是否设置为自动生成建表语句。
-->
<!-- <property name="hbm2ddl.auto">update</property> -->
<mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>
</session-factory>
设置Student类/属性和数据库表/字段之间的对应关系:建立Student.hbm.xml(Student.java放在同一个包下) 查阅文件1:关于映射文件的描述,我们可以对此创建出如下配置文件。
例4:
<?xml version="1.0"?><!--
如果实体类(name="Student")和数据库表名字(table="student")一样(忽略大小写),可以不必配。
-->
<class name="Student">
<!--
id对应数据库表的主键
name="id" 指的是类中getId的方法
column="_id" 指的是对应在数据库中的表字段名称
如果name和column名字一样,那么我们只写一个name就行
-->
<id name="id"></id>
<!-- property 写其他字段 -->
<property name="name"></property>
<property name="age"></property>
</class>
修改hibernate.cfg.xml的mapping标签,链接student.hbm.xml的位置。 例5: 修改测试类studentTest.java public class StudentTest { public static void main(String[] args) { Student s = new Student(); s.setId(1); s.setAge(18); s.setName("s1"); //拿到Configuration对象 Configuration cfg = new Configuration(); //cfg.configure();不写参数,默认也是找hibernate.cfg.xml //生成sessionfactory SessionFactory sf = cfg.configure().buildSessionFactory(); Session session = sf.openSession(); session.beginTransaction();//开启事务管理 //保存Student对象 把数据放入一级缓存session中的操作 session.save(s); //根据session获得一个Transaction实例 //此处才是真正与数据库交互的语句 //提交事务 session.getTransaction().commit(); session.close(); sf.close(); } } 10)运行测试类结果如下:
Hibernate: insert into Student (name, age, id) values (?, ?, ?)
11)在数据库中查询后结果如下:
说明s1对象已经插入数据库中。
第二个hibernate程序:建立Annotation(注解)版本的HelloWorld
在hibernate3之后支持annotation.
1)创建一个Teacher.java类
例6:
public class Teacher {
private int id;
private String name;
private String title;//职称
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 getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
2)在数据库中建立好teacher表
3) 导入annotation相关包
在Teacher.java上添加注解@Entity
例7:Teacher.java
import javax.persistence.Entity;
@Entity
public class Teacher {
… …
}
由包路径可知,此注解并不属于hibernate,而是一个标准,hibernate实现了它,并且hibernate实现的比原来的更好。
“三流公司买产品,二流公司卖服务,一流公司卖标准。”所以此标准定义的和hibernate非常符合。
5)在Teacher.java上添加注解@Id,代表数据库中的主键字段。
例8:Teacher.java
@Id
public int getId() {
return id;
}
6)添加对应在hibernate.cfg.xml的mapping标签(可以跟之前使用配置文件配置作对比)
例9:hibernate.cfg.xml
7)测试类TeacherTest.java例10:
public class TeacherTest {
public static void main(String[] args) {
Teacher t1 = new Teacher();
t1.setId(1);
t1.setName(“t1”);
t1.setTitle(“middle”);
Configuration cfg = new AnnotationConfiguration();
SessionFactory sf = cfg.configure().buildSessionFactory();
Session session = sf.openSession();
session.beginTransaction();
session.save(t1);
session.getTransaction().commit();
session.close();
sf.close();
}
}
运行测试类,结果如下:
Hibernate: insert into Teacher (name, title, id) values (?, ?, ?)
例11:在数据库中查询结果如下图所示
常见的一个小问题:
@不给提示:content assist --> activation -->加上@
What is and Why O/R Mapping
相比较JDBC操作数据库,流程大大简化。
Sql语句本身并不是面向对象的。
可以在对象和关系表之间建立关联来简化编程。
O/R Mapping 可以跨数据库平台
O/R Mapping 可以简化编程
模拟实现hibernate
创建出一个新的Java project:Hibernate_0200_OR_Mapping_Simulation,
导入mysql-connector-java相关包。
第一步:创建Student.java
例12:Student.java
public class Student {
private int id;
private String name;
private int age;
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
例13:StudentTest.java
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
s.setId(2);
s.setAge(18);
s.setName(“s1”);
//此session是我们自己定义的
Session session = new Session();
session.save(s);
}
}
例14:Session.java
public class Session {
String tableName = "_Student";
//属性和表字段一一对应
//以下东西应该是配置文件配置
Map<String,String> cfs = new HashMap<String,String>();
public Session() {
cfs.put("_id", "id");
cfs.put("_name", "name");
cfs.put("_age", "age");
}
public void save(Student s){
String sql = createSQL();
System.out.println(sql);
}
private String createSQL() {
String str1 = "";
for (String s : cfs.keySet()) {
str1 += s+",";
}
str1 = str1.substring(0,str1.length()-1);
String str2 = "";
for (int i = 0; i < cfs.size(); i++) {
str2 += "?,";
}
str2 = str2.substring(0,str2.length()-1);
/*str1:指的是用key形成的String
*str2:指的是用value形成的String
*/
String sql = "insert into " + tableName + "("+ str1 +")"
+ "values (" + str2 + ")";
return sql;
}
}
运行测试类,结果如下:
insert into _Student(_id,_age,_name)values (?,?,?)
SQL语句成功打印出来,接下来我们需要连接数据库。
第二步:连接数据库
在数据库中新建table _Student,如下图所示:
修改Session.java如下
例15:
public class Session {
String tableName = “_Student”;
//属性和表字段一一对应
//以下东西应该是配置文件配置
Map<String,String> cfs = new HashMap<String,String>();
String[] methodNames;
public Session() {
cfs.put("_id", "id");
cfs.put("_name", "name");
cfs.put("_age", "age");
methodNames = new String[cfs.size()];
}
public void save(Student s) throws Exception{
String sql = createSQL();
//连接数据库
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/hibernate", "root", "root");
//创建Statement
PreparedStatement ps = conn.prepareStatement(sql);
/*如何设值(拿到对象的具体属性值设置到相应的字段)**/
//使用反射机制
for (int i = 0; i < methodNames.length;i++) {
//拿到方法的原型
Method m = s.getClass().getMethod(methodNames[i]);
/*
* System.out.println(m);
* 可得:
* public int com.hibernate.model.Student.getId()
public int com.hibernate.model.Student.getAge()
public java.lang.String com.hibernate.model.Student.getName()
*/
//我们拿到方法的返回值类型,就可以用对应的类型插入数据库
Class r = m.getReturnType();
/*System.out.println(r.getName());
*可得: int
int
java.lang.String
*/
//再做判断
if(r.getName().equals("int")){
Integer returnValue = (Integer) m.invoke(s);
ps.setInt(i+1, returnValue);//数据库从第一行开始
}
if(r.getName().equals("java.lang.String")){
String returnValue = (String) m.invoke(s);
ps.setString(i+1, returnValue);
}
}
//真正往数据库插入数据
ps.executeUpdate();
ps.close();
conn.close();
}
private String createSQL() {
String str1 = "";
int index = 0;
for (String s : cfs.keySet()) {
String value = cfs.get(s);
methodNames[index] = "get"+Character.toUpperCase(value.charAt(0))+value.substring(1);
str1 += s+",";
index++;
}
str1 = str1.substring(0,str1.length()-1);
String str2 = "";
for (int i = 0; i < cfs.size(); i++) {
str2 += "?,";
}
str2 = str2.substring(0,str2.length()-1);
/*str1:指的是用key形成的String
*str2:指的是用value形成的String
*/
String sql = "insert into " + tableName + "("+ str1 +")"
+ "values (" + str2 + ")";
return sql;
}
}
例16:StudentTest.java
public class StudentTest {
public static void main(String[] args) throws Exception {
Student s = new Student();
s.setName("s1");
s.setId(2);
s.setAge(18);
//此session是我们自己定义的
Session session = new Session();
session.save(s);
}
}
运行测试类,控制台无结果。
在mysql中查询结果如下,说明我们插入成功。以后我们再插入Student对象就不必写sql语句了!
总结
本章我们讲了在hibernate中使用xml和annotation配置的流程,模拟了hibernate原理,
希望大家通过这些案例理解了什么是O/R Mapping.
私信小编,领取2019最新算法、设计模式、hadoop+企业级BI、AI架构视频资料
腾讯公开课,免费报名,领取资料