Java ORM一个字形容:乱;两个字:很乱;三个字:非常乱。
但马马虎虎勉勉强强可以选两大巨头:Hibernate和myBatis(如果myBatis也算是ORM的话)
选择Hibernate教学,主要是因为她:
2001年11月:27岁(英雄出少年啊!)澳大利亚程序员Gavin King,发布Hibernate 1.0版本,免费开源,历史悠久。
2003年9月:Hibernate开发团队加入JBoss公司,开始全职开发。
2006年:JPA(Java Persistent API,持久化框架标准)发布,Hibernate在3.2版本开始,已经完全兼容JPA标准。
PS:因为JPA最主流最强大的实现就是Hibernate,所以经常看到有人把JPA和Hibernate混为一谈。其实实现JPA标准的还有:EclipseTop、OpenJPA、Spring Data JPA……
版本选择:5.1,略新,2018年底发布final版(实际开发中怕是3.0版本的多,但飞哥也要考虑收视率……)
尽量简洁:如无必要,ABC三种方案都可以实现,就只讲最主流最方便的一种(尽量以JPA为准,此外还有hibernate保留的独有的native),不铺开了……
<dependency> <groupId>org.hibernate</groupId> <!-- 因为要使用JPA模式,所以是entitymanager;否则Java-8 --> <artifactId>hibernate-entitymanager</artifactId> <version>5.1.17.Final</version> </dependency>核心jar包:
按照JPA的要求(native的要求略弱)准备了Student类:
public class Student { private int id; private String name; public int getId() { return id; } public void setId(int id) {
这样和普通Java类没有区别(比如没有要求必须继承自某个基类)的entity又被称之为POJO(Plain Old Java Object,简单的Java对象)。
PS:怎么才不普通?有些ORM要求所有的entity必须继承自某个基类啥的……
由于entity都是POJO,我们还需要告诉hibernate哪些类是需要映射的entity。可以选择:
import javax.persistence.Entity; @Entity //标明这个类是entity public class Student { @Id //JPA要求entity必须有一个主键 private int id;
按JPA规范要求,接下来需要一个persistence.xml文件,进行一些配置,告诉hibernate如何连接数据库等信息……
PS:如果是native模式的话,需要hibernate.cfg.xml文件
你在读文档的时候会看到classpath,比如:
(Hibernate in this case) is required to locate all JPA configuration files by classpath lookup of the META-INF/persistence.xml resource name.
classpath是JVM用到的一个环境变量,它用来指示JVM如何搜索java类文件。
不同的项目有不同的classpath(还可以自定义设定)。
演示:eclipse中查看全局/项目的class path
eclipse演示:新建一个xml文件
以下部分只需要复制粘贴即可:
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1"> </persistence>persistence下面可以有若干个persistence-unit(持久化单位):
<!-- name自定义,后面有用 --> <persistence-unit name="mysql-jpa"> </persistence-unit>实际开发中可能连接多个/种数据库,每个/种连接都可以定义一个persistence-unit。
persistence-unit下首先要定义一个provider(详见后文):
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
然后是若干properties,首先是和JDBC连接字符串对应的连接信息:
<properties> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/17bang" /> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="" /> </properties>
首先导入:
import javax.persistence.*;
JPA也使用的工厂模式
private static EntityManagerFactory entityManagerFactory; static { entityManagerFactory = Persistence.createEntityManagerFactory( "mysql-jpa" /* persistence-unit中定义的名字! */ ); }
演示运行:正确配置,有log生成(persistence-unit/driver/connection pool/ dialect等)
可以在persistence-unit中添加一个property:
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
这样Hibernate在生成EntityManagerFactory的时候,根据entity映射配置和它的value值,自动的:
这些操作都是通过生成SQL语句完成的。
有时候(比如生产环境部署)我们还需要拿到这些SQL语句,这时候我们就需要额外的配置:
<property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create" />value值指示何时生成SQL脚本。
生成的SQL脚本会保存到文件中,所以,还需要指定文件路径:
<property name="javax.persistence.schema-generation.scripts.drop-target" value="sqlscript/drop.sql" /> <property name="javax.persistence.schema-generation.scripts.create-target" value="sqlscript/create.sql" />
删除表的SQL(drop-target)和更新表(create-target,包含create和update)的SQL脚本需要分开存放。
默认生成的SQL语句没有换行和缩进,以下配置可以格式化的输出SQL语句:<property name="hibernate.format_sql" value="true"/>
F3和断点演示:createEntityManagerFactory()中调用getProviders()
实际上通过配置文件获得了类:
public class HibernatePersistenceProvider implements PersistenceProvider {
这个类实现了PersistenceProvider接口,用于构建entityManagerFactory(复习:session factory)
#理解:通过provider模式(仍然是API和实现分离),可以利用配置在不同的provider间灵活的切换
private boolean isMale; //bit private float score; //float private int age; //integer private DayOfWeek rest; //integer private String description; //varchar(255) private UUID uid; //binary
演示:默认映射效果
很多时候,hibernate默认的映射不能完全满足我们的需求,所以还需要自定义的映射。
我们仍然采用annotation的方式,目前两种annotation都可以使用:
import javax.persistence.*; //以persistence为主,所以*概括 import org.hibernate.annotations.Check; //hibernate为辅,所以要指明具体类型 import org.hibernate.annotations.Nationalized;
自动生成:
@GeneratedValue( strategy = GenerationType.IDENTITY ) //id integer not null auto_increment,
@GeneratedValue private UUID id; //uid binary(255),
改列名:
@Column(name = "sname") //sname varchar(255),
可空:(默认都是不可空的)
@Column(nullable = true) //isMale bit,
设置默认值(传入的始终是字符串)
@ColumnDefault("18") //age integer default 18 not null,
设定文本/字符串的
@Column(length = 50) //sname varchar(50),
@Nationalized //sname nvarchar(50),
@Lob //description longtext,
设定小数位数(必须使用BigDecimal):
@Column(precision = 5, scale = 2) private BigDecimal score; //score decimal(5,2),
PS:@Column里面还可以有多个并列的描述。
添加唯一约束:
@Column(unique = true)
但这样生成的unique约束名是mysql的“乱码”名(实际上是根据表名列名等编码所得)
alter table Student add constraint UK_tlswl9chftpfrcq9o86kys6ug unique (sname)
如果要使用自定义的名称,要在注解类的@Table中声明
private Date enroll; private Calendar created;如果我们能确定只使用日期,可以添加一个:
@Temporal(TemporalType.DATE) //enroll date,
能够稍微节省一点空间。
但对于Java8引入的LocalDateTime、LocalDate和LocalTime,需要maven引入
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-java8</artifactId> <version>5.1.17.Final</version> </dependency>才能映射成datetime、date或time,¯\_(ツ)_/¯
private LocalDate enroll; //enroll date, private LocalDateTime created; //created datetime,否则会映射成tinyblob类型,哈哈……
改表名:
@Table(name = "T_Student")自定义检查:(注意:不要标记在字段上!)
@Check(constraints = "age>0")
唯一约束
@Table(uniqueConstraints = { //columnNames是表上真实的列名 @UniqueConstraint(name = "UK_Name", columnNames = { "sname" }) } )
如果要定义约束名称的话,只能这样。还可以多列组合约束
新建索引:@Table(indexes = { @Index(name = "IX_Name", columnList = "name", unique = true) }
注意这些annotation只是确定表结构的生成,不校验/影响entity的生成。比如@ColumnDefault("18")并不会在我new一个Student()的时候给age自动赋值成18.
多快好省!前端后端,线上线下,名师精讲
更多了解 加: