1、hibernate是开源的轻量级的对象关系映射框架,用了ORM思想,对jdbc进行了封装。
2、ORM(Object-Relation Mapping)对象关联映射。
3、hibernate配置文件默认名字为hibernate.cfg.xml或者hibernate.properties,当调用Configuration config = new Configuration().configure()则加载默认名字的配置文件。如果写死加载某个配置则Configuration config = new Configuration().configure(new File(strPath))或者Configuration config = new Configuration().configure(strPath)
4、hibernate配置文件示例
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC" //Hibernate/Hibernate Configuration DTD/EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--数据库驱动类-->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!--数据库连接url-->
<property name="connection.url">jdbc:mysql://localhost:3306/mytest</property>
<!--数据库连接用户名-->
<property name="connection.username">root</property>
<!--数据库连接密码-->
<property name="connection.password">root</property>
<!--sql方言-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!--显示sql语句-->
<property name="show_sql">true</property>
<!--根据映射文件在数据库创建表-->
<property name="hbm2ddl.auto">create</property>
<!--c3p0连接池-->
<property name="c3p0.min_size">5</property>
<property name="c3p0.max_size">20</property>
<property name="c3p0.timeout">1800</property>
<!-- 最大的PreparedStatement的数量 -->
<property name="c3p0.max_statements">50</property>
<!-- 每次都验证连接是否可用 -->
<property name="c3p0.validate">true</property>
<!-- 当连接池里面的连接用完的时候,c3p0获取的新的连接数 -->
<property name="c3p0.acquire_increment">2</property>
<!--每隔多少秒就检查连接池里面的空闲连接-->
<property name="c3p0.idle_test_period">120</property>
<!--表和类的映射文件-->
<mapping resource="org/model/User.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
5、SessionFactory和Session
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
6、主键关系的双向一对一
创建表,虽然可以用hibernate配置表的关系,但是为了数据严谨还是在表结构上也加上外键约束
create table man(
id int primary key auto_increment,
name varchar(20)
);
create table women(
id int primary key,
name varchar(20),
foreign key(id) references man(id)
);
Man.java类属性:private Integer id;private String name;private Women women;
Women.java类属性:private Integer id;private Man man;private String name;
Man.hbm.xml映射文件:outer-join代表外联查询默认是true,cascade表示级联操作默认为none,其值有all、none、save-update、delete
<hibernate-mapping>
<class name="com.bean.Man" table="man" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="assigned" />
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<one-to-one name="women" class="com.bean.Women" outer-join="false" cascade="all"/>
</class>
</hibernate-mapping>
Women.hbm.xml映射文件:id里面的generator的class="foreign"表示本id由外键提供。param元素的值代表本类哪个字段用,该字段代表外键
<hibernate-mapping>
<class name="com.bean.Women" table="women" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="foreign">
<param name="property">man</param>
</generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<!--constrained="true"表示本表主键存在外键约束,通常跟generator元素的class="foreign"同时出现的-->
<one-to-one name="man" class="com.bean.Man" constrained="true"/>
</class>
</hibernate-mapping>
7、唯一外键关系的双向的一对一
创建表,虽然可以用hibernate配置表的关系,但是为了数据严谨还是在表结构上也加上外键约束
create table man(
id int primary key auto_increment,
name varchar(20)
);
create table women(
id int primary key auto_increment,
name varchar(20),
mid int unique,
foreign key(mid) references man(id)
);
Man.java类属性:private Integer id;private String name;private Women women;
Women.java类属性:private Integer id;private String name;private Man man;
Man.hbm.xml映射文件:outer-join指的是是否外联查询,默认是true。cascade表示级联操作默认为none,其值有all、none、save-update、delete
<hibernate-mapping>
<class name="com.bean.Man" table="man" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<one-to-one name="women" class="com.bean.Women" cascade="all"/>
</class>
</hibernate-mapping>
Women.hbm.xml映射文件:fetch是指查询方式其值为join(表示通过outer join来查询即是只有一条sql语句)、select(表示另外发一条sql语句来查询对象的关联实体或集合,相对于第一条sql为延迟加载)。另外fetch会使得outer-join属性无效
<hibernate-mapping>
<class name="com.bean.Women" table="women" catalog="mytest" >
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<many-to-one name="man" class="com.bean.Man" fetch="select">
<column name="mid" unique="true" />
</many-to-one>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
</class>
</hibernate-mapping>
8、延迟加载配置
<class lazy="true">其值为:true、false,默认ture,加载类对象。如果为false那么会使得session.load(,)方法无效
<one-to-one lazy="">其值为:false、proxy、no-proxy,加载类对象的关联对象
<many-to-one lazy="">其值为:false、proxy、no-proxy,加载类对象的关联对象
<set lazy="">其值为:true、false、extra,加载类对象的关联集合对象
9、单向多对一
创建表(person为多的一方)
create table room(
id int primary key auto_increment,
address varchar(20)
);
create table person(
id int primary key auto_increment,
name varchar(10),
rid int,
foreign key(rid) references room(id)
);
Room.java类属性:private Integer id;private String address;
Person.java类属性:private Integer id; private Room room;private String name;
Room.hbm.xml映射文件
<hibernate-mapping>
<class name="com.bean.Room" table="room" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<property name="address" type="java.lang.String">
<column name="address" length="20" />
</property>
</class>
</hibernate-mapping>
Person.hbm.xml映射文件
<hibernate-mapping>
<class name="com.bean.Person" table="person" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<many-to-one name="room" class="com.bean.Room" fetch="select" cascade="all">
<column name="rid" /><!--指的是person表的rid-->
</many-to-one>
<property name="name" type="java.lang.String">
<column name="name" length="10" />
</property>
</class>
</hibernate-mapping>
10、双向一对多
把上一例子中的Room.java增加一个属性
Room.java类属性:private Integer id;private String address;private Set persons = new HashSet();
把上一例子中的Room.hbm.xml修改编程双向关联
inverse属性表示维护权反转,值为false表示由Room维护,值为true表示由Person维护,默认为false即是由自己维护。一般把其设为true。
以下面例子解析:
如果为false那么主外键关系由Room维护。
先执行添加Room对象
再执行添加2个Person对象(person表的rid是从p.getRoom().getId()而来的)
最后会对那两个Person对象的rid进行更新,更新为Room对象的rid(直接从r.getId()而来的)
总结:inverser=false最后会有更新Person的外键rid的语句(多少条语句?由这个Room对象添加了多少个Person决定),这种方法比较严谨的保证数据不乱,但是也影响了效率。
如果为true那么主外键关系有PersonW维护。
先执行添加Room对象
再执行添加2个Person对象(person表的rid是从p.getRoom().getId()而来的)
总结:inverse=true最后没有更新Person的外键rid的语句,这种方法会高效,但是必须保证Person中有Room对象、Room对象中有Person对象才使得数据不会乱。
比如room添加了person1和person2,如果person2没有把room对象set进去那么session.save(room)结果person2是没有room的,但是我们以为person2已经对应room了。
Session session = HibernateSessionFactory.getSession();
Room r = new Room();
r.setAddress("address1");
Person p1 = new Person();
p1.setName("p1");
p1.setRoom(r);
Person p2 = new Person();
p2.setName("p2");
//Room r2 = (Room) session.get(Room.class, 2);
//r2.setId(2);
//p2.setRoom(r2);
p2.setRoom(r);
r.getPersons().add(p1);
r.getPersons().add(p2);
session.save(r);
session.beginTransaction().commit();
<hibernate-mapping>
<class name="com.bean.Room" table="room" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<property name="address" type="java.lang.String">
<column name="address" length="20" />
</property>
<set name="persons" inverse="false" cascade="all">
<key>
<column name="rid" /><!--指的是person表的rid-->
</key>
<one-to-many class="com.bean.Person"/>
</set>
</class>
</hibernate-mapping>
11、双向多对多(不需要桥表的bean和桥表的映射文件inverse属性不能同时相同即是只能由某一方维护)
表结构:通过hibernate配置是不用桥表的,但是为了数据严谨还是在数据库上建立桥表。
create table player(
id int primary key auto_increment,
name varchar(20)
);
create table game(
id int primary key auto_increment,
name varchar(20)
);
create table p_g_bridge(
id int primary key auto_increment,
pid int,
gid int,
foreign key(pid) references player(id),
foreign key(gid) references game(id),
unique(pid,gid)
);
Player.java属性private Integer id;private String name;private Set games = new HashSet(0);
Game.java属性 private Integer id;private String name;private Set players = new HashSet(0);
Player.hbm.xml映射文件:需要设置set元素的table属性为桥表的名字
<hibernate-mapping>
<class name="com.bean.Player" table="player" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<set name="games" inverse="true" table="p_g_bridge" cascade="save-update" >
<key column="pid" />
<many-to-many class="com.bean.Game" column="gid"/>
</set>
</class>
</hibernate-mapping>
Game.hbm.xml映射文件:需要设置set元素的table属性为桥表的名字
<hibernate-mapping>
<class name="com.bean.Game" table="game" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<set name="players" inverse="false" table="p_g_bridge" cascade="save-update">
<key column="gid"/>
<many-to-many class="com.bean.Player" column="pid" />
</set>
</class>
</hibernate-mapping>
12、双向多对多(把维护权交给桥表,两个表与桥表形成一对多关系)
表结构:通过hibernate配置是不用桥表的,但是为了数据严谨还是在数据库上建立桥表。
create table player(
id int primary key auto_increment,
name varchar(20)
);
create table game(
id int primary key auto_increment,
name varchar(20)
);
create table p_g_bridge(
id int primary key auto_increment,
pid int,
gid int,
foreign key(pid) references player(id),
foreign key(gid) references game(id),
unique(pid,gid)
);
Player.java属性private Integer id;private String name;private Set PGBridges = new HashSet(0);
Game.java属性private Integer id; private String name;private Set PGBridges = new HashSet(0);
PGBridge.java属性private Integer id; private Game game;private Player player;
Player.hbm.xml映射文件
<hibernate-mapping>
<class name="com.bean.Player" table="player" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<set name="PGBridges" inverse="true" cascade="save-update">
<key>
<column name="pid" /><!--指桥表的pid列-->
</key>
<one-to-many class="com.bean.PGBridge" />
</set>
</class>
</hibernate-mapping>
Game.hbm.xml映射文件
<hibernate-mapping>
<class name="com.bean.Game" table="game" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<set name="PGBridges" inverse="true" cascade="save-update">
<key>
<column name="gid" /><!--指桥表的pid列-->
</key>
<one-to-many class="com.bean.PGBridge" />
</set>
</class>
</hibernate-mapping>
PGBridge.hbm.xml映射文件
<hibernate-mapping>
<class name="com.bean.PGBridge" table="p_g_bridge" catalog="mytest">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<many-to-one name="game" class="com.bean.Game" fetch="select" cascade="save-update">
<column name="gid" /><!--本表的pid列-->
</many-to-one>
<many-to-one name="player" class="com.bean.Player" fetch="select" cascade="save-update">
<column name="pid" /><!--本表的pid列-->
</many-to-one>
</class>
</hibernate-mapping>
13、实体声明周期
临时态transient:实体对象在内存中并且与数据库的记录无关。
持久态persistent:临时状态的对象被session对象保存、查询、更新成为持久太。被session维护
游离态detached:持久态的对象被session删除或者session关闭成为游离态。不再被session维护
14、一级缓存:是指session管理的缓存默认存在并且不允许卸载的用get和load方法查询都会先去一级缓存里面查找的。
清空一级缓存:session.flush()方法
15、二级缓存:是指SessionFactory管理的缓存是共享的是可以开启和关闭的。
使用二级缓存步骤:
一、在hibernate.cfg.xml配置文件配置<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>这个类位于org.hibernate.cache下。
二、在类映射文件里面的class元素里面加上子元素<cache usage="read-write" />usage还可以read-only、write-only。或者在hibernate.cfg.xml配置文件里面加上<class-cache class="com.bean.Ttt" usage="read-only"/>
三、根据步骤一的提供商(根据提供商而定)。如果需要配置二级缓存的细节则需要在hibernate.cfg.xml同一级目录下新建一个ehcache.xml文件
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache>
maxElementsInMemory="10000"<!--缓存中对象个数最大为10000-->
eternal="false"<!--缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期-->
timeToIdleSeconds="120"<!--缓存数据钝化时间(设置对象在它过期之前的空闲时间)-->
timeToLiveSeconds="120"<!--缓存数据的生存时间(设置对象在它过期之前的生存时间)-->
overflowToDisk="true"<!--内存不足时,是否启用磁盘缓存 -->
</defaultCache>
</ehcache>
如果找不到这个文件则去找默认的配置文件ehcache-failsafe.xml文件(位于ehcache.jar包下的),文件内容是:
<ehcache>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>
注意:如果不是load和get方法而是Query query=session.createQuery(strSql)则需要把query.setCacheable(true)意思是允许本查询去查询缓存里面的数据。
再注意:一级缓存、二级缓存、直接查询数据,速度依次降低。
关闭二级缓存:在hibernate.cfg.xml配置<property name="cache.use_second_level_cache">false</property>
清空二级缓存里面的数据:sessionFactory.evict(class)或者sessionFactory.evict(class,id)
16、查询缓存
查询缓存默认不开启,如果要开启:在hibernate.cfg.xml配置<property name="cache.use_query_cache">true</property>
如果不开启那么查询缓存数据只能是通过id查询。开启后可以通过条件查询来查询缓存数据。
17、批量处理
需要配置:在hibernate.cfg.xml里面加上<property name="jdbc.batch_size">50</property>意思是批量提交的话每50条就去处理。
注意:批量处理的话建议关闭二级缓存,提交效率。
18、注解
一、声明实体
@Entity
@Table(name="表名")
@Id 位于id属性声明的上一行或者在get方法上一行(前提是get方法的名称是由get+MethodName构成的)
@GeneratedValue (strategy =GenerationType.AUTO) 位于@Id下方 表示自动增长,不写就是自动的
@Column (name = "表的列名"s) 位于实体属性声明的上面或者在get方法上一行(前提是get方法的名称是由get+MethodName构成的)
@Transient注明属性不映射到表上或者在get方法上一行(前提是get方法的名称是由get+MethodName构成的)
二、在hibernate.cfg.xml文件加入元素<mapping class="包名+类名" />
三、使用方法
Configuration config = new AnnotationConfiguration().configure();
SessionFactory factory = config.buildSessionFactory();
Session session = factory.openSession();
例子:
表结构
create table ttt(
id int primary key auto_increment,
name varchar(20)
);
Ttt.java实体类
@Entity
@Table(name="ttt")
public class Ttt implements java.io.Serializable {
@Id
@GeneratedValue (strategy =GenerationType.AUTO)
private Integer id;
@Column (name = "name")
private String name;
public Ttt() {
}
public Ttt(String name) {
this.name = name;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
19、注解双向一对一
Body.java
@Entity
public class Body {
private int id;
private String name;
private Heart heart;
@Id
@GeneratedValue
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;
}
@OneToOne(cascade=CascadeType.ALL)//级联
@JoinColumn(name="h_id",unique=true)//设置外键列名并加唯一约束
public Heart getHeart() {
return heart;
}
public void setHeart(Heart heart) {
this.heart = heart;
}
}
Heart.java类
@Entity
public class Heart {
private int id;
private String name;
private Body body;
@Id
@GeneratedValue
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;
}
@OneToOne(mappedBy="heart")//指向关联实体的hear属性。本实体Heart的body属指向关联实体Body的heart属性
public Body getBody() {
return body;
}
public void setBody(Body body) {
this.body = body;
}
}
20、注解多对一
Department.java类
@Entity
@Table(name="t_dept")
public class Department {
private int id;
private String dept_name;
private Organizaiton org;
@ManyToOne//多对一
@JoinColumn(name="abc")
public Organizaiton getOrg() {
return org;
}
public void setOrg(Organizaiton org) {
this.org = org;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDept_name() {
return dept_name;
}
public void setDept_name(String deptName) {
dept_name = deptName;
}
}
Organization.java类
@Entity
@Table(name="t_org")
public class Organizaiton {
private int id;
private String org_name;
@Id @GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getOrg_name() {
return org_name;
}
public void setOrg_name(String orgName) {
org_name = orgName;
}
}
20、注解双向一对多
Orgnization.java类,一的一方
@Entity
@Table(name="t_org")
public class Organizaiton {
private int id;
private String org_name;
private Set<Department> dept;
@Id @GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@OneToMany(mappedBy="org")//把维护权给对方Department
@JoinColumn(name="org_id")
public Set<Department> getDept() {
return dept;
}
public void setDept(Set<Department> dept) {
this.dept = dept;
}
public String getOrg_name() {
return org_name;
}
public void setOrg_name(String orgName) {
org_name = orgName;
}
}
Department.java类,多的一方
@Entity
@Table(name = "t_dept")
public class Department {
private int id;
private String dept_name;
private Organizaiton org;
@ManyToOne
@JoinColumn(name="org_id")
public Organizaiton getOrg() {
return org;
}
public void setOrg(Organizaiton org) {
this.org = org;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDept_name() {
return dept_name;
}
public void setDept_name(String deptName) {
dept_name = deptName;
}
}
20、注解双向多对多
User.java类
@Entity
public class User {
private int id;
private String name;
private Set<Role> roles = new HashSet<Role>();
@ManyToMany
/**
* 默认,hibernate会自动创建一个中间表,来维护多对多关系
* */
@JoinTable(name="t_user_role",
joinColumns={@JoinColumn(name="u_id")},
inverseJoinColumns={@JoinColumn(name="r_id")}
)
/**
* @JoinTable(name="t_user_role")指定中间表名称
* joinColumns={@JoinColumn(name="u_id")}指定对象的外键
* inverseJoinColumns={@JoinColumn(name="r_id")}指定关联对象的外键
* */
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
@Id @GeneratedValue
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;
}
}
Role.java类
@Entity
public class Role {
private int id;
private String name;
private Set<User> users = new HashSet<User>();
@ManyToMany
@JoinTable(name="t_user_role",
joinColumns={@JoinColumn(name="r_id")},
inverseJoinColumns={@JoinColumn(name="u_id")}
)
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
@Id @GeneratedValue
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;
}
}