介紹
概述
ORM體現(xiàn)
是JBoss公司的產(chǎn)品
下載
http://www.hibernate.org
http://hibernate.org/orm/downloads/
https://sourceforge.net/projects/hibernate/files/hibernate-orm/
https://sourceforge.net/projects/hibernate/files/
解壓后文件夾說明
documentation : 全部的文檔
devguide : 開發(fā)指導.
javadocs : api文檔.
manual : 開發(fā)指南.
quickstart : 快速開始.
lib: 存放了所有的jar(第三方的、自己的).
required : 必須要的jar.
jpa : jpa實現(xiàn)的jar.
optional: 可選的.
c3p0 : 連接池(現(xiàn)在企業(yè)用得最多的連接池).
ehcache : 緩存框架.
proxool : 連接池.
project : 存放了Hibernate框架的源碼、測試用例、資源文件、示例.
project/etc : 存放了配置文件的模版.
基礎的jar包
required + jpa + mysql數(shù)據(jù)庫連接
使用步驟:
1.建庫、建表
2.寫實體類
3.映射實體類
1.映射文件(不流行)-hibernate包中搜索*.hbm.xml。配置文件要和實體類在一個包下。
2.使用jpa注解(流行)
4.寫hibernate配置文件
配置屬性 hibernate-release-4.3.11.Final\project\etc\hibernate.properties
5.測試api
hibernate配置文件說明
參考 hibernate-distribution-3.6.0.Final\project\etc\hibernate.properties
hibernate.connection.driver_class
指定數(shù)據(jù)庫連接參數(shù)
com.mysql.jdbc.Driver
hibernate.connection.url
如果數(shù)據(jù)庫不存在就建庫
jdbc:mysql:///hib_demo?createDatabaseIfNotExist=true
hibernate.connection.username
數(shù)據(jù)庫用戶名
hibernate.connection.password
數(shù)據(jù)庫密碼
hibernate.dialect
配置數(shù)據(jù)庫方言(指定使用哪一種數(shù)據(jù)庫,hibernate會根據(jù)這里指定的方言,生成符合當前數(shù)據(jù)庫語法的sql語句)
org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql
顯示hibernate在運行的時候生成的sql語句!
true
hibernate.format_sql
格式化sql
true
hibernate.hbm2ddl.auto
自動建表
update
表不存在則創(chuàng)建,如果表已經(jīng)存在就不創(chuàng)建表
create
先刪除表,再創(chuàng)建一個新表
create-drop
在創(chuàng)建SessionFactory時候建表;在執(zhí)行其close方法的時候刪除表
validate
驗證;檢查映射配置與表結(jié)構(gòu)是否一致,不一致報錯!更嚴格!
javax.persistence.validation.mode
關閉java對象注解驗證!(如果新建web項目,使用javaee6.0以上版本,必須要加上這行!)
none
基本使用代碼一
User.java
public class User {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
User.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.shuai.domain.User" table="t_user">
<id name="id" column="uid">
<generator class="uuid"></generator>
</id>
<property name="name" column="uname"></property>
</class>
</hibernate-mapping>
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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hib_demo?createDatabaseIfNotExist=true</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="javax.persistence.validation.mode">none</property>
<mapping resource="cn/itcast/entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
AppTest.java
@Test
public void Save() throws Exception {
User user = new User();
user.setName("Jack");
//1. 創(chuàng)建配置管理器對象
Configuration config = new Configuration();
//2. 加載主配置文件:hibernate.cfg.xml
config.configure();
//3. 創(chuàng)建SessionFactory對象
SessionFactory sf = config.buildSessionFactory();
//4. 創(chuàng)建Session (會話,與數(shù)據(jù)庫的連接的會話)
Session session = sf.openSession();
//5. 開啟事務
Transaction tx = session.beginTransaction();
//6. -- 執(zhí)行操作--
session.save(user);
//7. 提交事務/關閉
tx.commit();
session.close();
}
@Test
public void get() throws Exception {
Configuration config = new Configuration();
config.configure();
SessionFactory sf = config.buildSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
User user = (User) session.get(User.class, 1);
System.out.println(user);
tx.commit();
session.close();
}
基本使用代碼二
User.java
@Entity
public class User {
@Id
private int id;
private String name;
private int age;
//getter/setter
}
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="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">32147</property>
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.min_size">2</property>
<mapping class="org.fkjava.hibernate.domain.User"/>
</session-factory>
</hibernate-configuration>
App.java
public void testAdd(){
// 第一步:創(chuàng)建Configuration配置信息對象 (加載全局的配置文件)
Configuration configuration = new Configuration() // 默認會加載src/hibernate.properties屬性文件
.configure(); // 默認會加載src/hibernate.cfg.xml
// 第二步:創(chuàng)建服務注冊對象
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
// 第三步:創(chuàng)建SessionFactory
SessionFactory sf = configuration.buildSessionFactory(serviceRegistry);
// 第四步:創(chuàng)建Session
Session session = sf.openSession();
// 第五步:開啟事務,得到事務對象
Transaction transaction = session.beginTransaction();
// 第六步:利用Session完成所有的持久化操作
User user = new User();
user.setId(1);
user.setAge(20);
user.setName("帥哥");
session.save(user);
// 第七步:事務提交或回滾 commit|rollback
transaction.commit();
// 第八步:關閉Session、SessionFactory
session.close();
sf.close();
}
API
hibernate3API
Configuration 管理管理文件的類
Configuration configure()
加載主配置文件,默認加載src/hibenrate.cfg.xml
SessionFactory buildSessionFactory()
創(chuàng)建session的工廠(hibernate.cfg.xml中就是session工廠的配置?。? 一個應用程序只需要一個session工廠即可!單例對象!
SessionFactory addClass(..)
加載指定類的字節(jié)碼對應的映射文件! (User.hbm.xml)
注意:
1.去對象所在的包下去找對應的映射文件;
2. 映射文件必須是*.hbm.xml后綴
3. 測試使用才去使用,比較方便!
SessionFactory session工廠
Session openSession()
創(chuàng)建新的session對象
Session getCurrentSession()
創(chuàng)建session (使用時候需要配置hibernate.cfg.xml)
(<property name="hibernate.current_session_context_class">thread</property>)
Session 與數(shù)據(jù)庫連接的會話!(里面維護了一個數(shù)據(jù)庫連接)
hibernate中操作數(shù)據(jù)庫就是通過session對象操作的!
Serializable save(obj);
保存對象 【主鍵自增長,就不用設置主鍵,設置了也沒有!】
void delete(obj);
刪除對象 【對象的主鍵一定要存在】
void update(obj);
修改對象 【對象的主鍵一定要存在】
void saveOrUpdate(obj);
保存或修改【有設置主鍵執(zhí)行更新,如果設置主鍵不存在就報錯! 沒有設置主鍵就保存!】
Object get(Class clazz,Serializable id);
主鍵查詢
查詢方式
1.寫HQL語句查詢【面向?qū)ο蟛樵儭? hibernate query language
hibernate提供的面向?qū)ο蟮牟樵冋Z句
實現(xiàn):session.createQuery(arg0);
2.Criteria查詢【面向?qū)ο蟛樵儭? session.createCriteria(sql);
3.本地sql查詢【支持原生態(tài)的sql語句查詢】
session.createSQLQuery(sql)
Transaction 事務
hibernate要求對數(shù)據(jù)庫數(shù)據(jù)的操作必須在一個事務環(huán)境內(nèi)進行!
Query
List list();
執(zhí)行的查詢的hql
int executeUpdate();
執(zhí)行的更新的hql
hibernate4
Configuration
專門負責加載全局的配置文件,產(chǎn)生SessionFactory.
ServiceRegistry
SessionFactory
它是當前數(shù)據(jù)庫在內(nèi)存中鏡像。一個SessionFactory對應一個數(shù)據(jù)庫,所以SessionFactory只能有一個,
當應用一啟動就獲取SessionFactory,當應用關閉時才關閉SessionFactory.
它是線程安全的.
它是創(chuàng)建Session的工廠。
它底層封裝了數(shù)據(jù)源(連接池)。
它還有一個可選的二級緩存. (默認是關閉的).
Session
概述
它是應用程序與持久層進行交互的單線程對象。
它是線程不安全。
它存活的時間比較短.(因為它底層封裝得是Connection,用完就要關閉).
它是事務工廠.
有一個必須開啟的一級緩存. (一級緩存永遠都是開啟的).
方法
contains(object);
判斷一級緩存中是否包含這個對象,true為持久化狀態(tài)
Transaction
Hibernate事務對象.
JDBC事務(局部事務) : 只能對一個數(shù)據(jù)庫中的表做事務. (web容器) tomcat jetty
JTA事務(全局事務、分布式事務) : 可以對多個數(shù)據(jù)庫中的表做事務.(EJB容器)
WebSphere(IBM)、WebLogic(Oracle)、JBoss(jboss)
ConnectionProvider
數(shù)據(jù)庫連接的提供者.
一般指得是數(shù)據(jù)源DataSource(連接池).
持久化類的狀態(tài)
Transient 瞬態(tài)
new 持久化類(),剛new出來的,從來沒有與Session關聯(lián)過.
Persistent 持久化狀態(tài)
正在被Session管理中。調(diào)用Session的方法對它進行操作過,這個時候Session沒有關閉.
該對象在Session一級緩存中. (在內(nèi)存中).
如果你調(diào)用持久化狀態(tài)對象的set方法,它會影響數(shù)據(jù)庫表中的數(shù)據(jù).
你對持久化狀態(tài)對象做的修改,會同步到底層的數(shù)據(jù)庫表中,它不是立即同步到底層的數(shù)據(jù)庫,默認是在事務提交時才同步。
Detached 脫管狀態(tài)
脫離了Session的管理,曾經(jīng)被Session管理過,現(xiàn)在沒被Session管理。
Hibernate的CRUD操作
Hibernate4添加:
a. Serializable id = session.save();
User user = new User(); // 瞬態(tài)
user.setXxx();
session.save(user); // user --> 持久化狀態(tài)
b. void session.persist();
User user = new User(); // 瞬態(tài)
user.setXxx();
session.persist(user); // user --> 持久化狀態(tài)
c. session.saveOrUpdate(); // 添加與修改
User user = new User(); // 瞬態(tài)
user.setXxx(); // 不要設置主鍵列對應的屬性.
void = session.saveOrUpdate(user); // user --> 持久化狀態(tài)
d. session.merge(); // 混合集成了添加與修改.
User user = new User(); // 瞬態(tài)
user.setXxx(); // 不要設置主鍵列對應的屬性.
User u = session.merge(user); // user --> 瞬態(tài),u --> 持久化狀態(tài)
注意:
save()與persist()區(qū)別
1.save方法有返回值,它返回的是主鍵id。
persist沒有返回值,需要通過對象的getId來獲取
2.save方法會立即往數(shù)據(jù)庫表中插入數(shù)據(jù)
persist方法會延遲往數(shù)據(jù)庫表中插入數(shù)據(jù)(跟事務是否開啟有關)
在事務開啟之后執(zhí)行這兩個方法做添加都會立即生成sql語句
Hibernate4根據(jù)主鍵查詢:
session.get(): 根據(jù)主鍵id查詢
User user = (User)session.get(User.class, 1); // user : 持久化狀態(tài)
立即從數(shù)據(jù)庫表查詢數(shù)據(jù),返回對象.
session.load(): 根據(jù)主鍵id查詢
User user = (User)session.load(User.class, 1); // user : 持久化狀態(tài)
延遲從數(shù)據(jù)庫表查詢數(shù)據(jù),一開始返回代理對象,當你真正要用到它的屬性時,
才會生成查詢語句到數(shù)據(jù)庫表中查詢數(shù)據(jù)。
當你要用到它的時候,要保證Session不能關閉。
Hibernate4修改:
持久化狀態(tài)下:
User user = (User)session.get(User.class, 1); // user : 持久化狀態(tài)
user.setXxx();
脫管狀態(tài)下:
User u = new User(); // 瞬態(tài)
u.setId(1); // 脫管
session.update(u); // u --> 持久化狀態(tài)
session.saveOrUpdate(u); // u --> 持久化狀態(tài)
User user = session.merge(u); // u --> 脫管 user --> 持久化狀態(tài)
Hibernate4刪除:
持久化狀態(tài)下:
User user = (User)session.get(User.class, 1); // user : 持久化狀態(tài)
session.delete(user); // user --> 瞬態(tài)
脫管狀態(tài)下:
User u = new User(); // u -> 瞬態(tài)
u.setId(3); // u -> 脫管
session.delete(u); // 瞬態(tài)
注解實現(xiàn)方式詳細介紹
注解作用
將持久化類轉(zhuǎn)換成表的相關信息.(表名,索引,唯一約束,列名的相關信息、關聯(lián))
基礎映射(注解加在持久化類上)
entity/table/DynamicInsert/DynamicUpdate/SelectBeforeUpdate
主鍵映射/復合主鍵映射
id/GeneratedValue/EmbeddedId
基本屬性映射(持久化類中屬性轉(zhuǎn)化成數(shù)據(jù)庫表中列的相關信息)
Column/Lob/Temporal/Transient
集合屬性映射
關聯(lián)映射
繼承映射
注解
第一類
類名上
@Entity
將POJO轉(zhuǎn)化成持久化類。
@Table
把持久化類轉(zhuǎn)化成表的相關信息
name:指定表名
schema :指定將數(shù)據(jù)表存入哪個數(shù)據(jù)庫,schema或者catalog只能指定一個.
catalog:指定將數(shù)據(jù)表存入哪個數(shù)據(jù)庫,schema或者catalog只能指定一個.
indexes: 用于指定表的引索列
@Index(columnList="數(shù)據(jù)表中的列名", name="索引名")
indexes={@Index(), @Index()}
uniqueConstraints:用于指定唯一約束
@uniqueConstraint(columnNames={"列名","列名"}, name="唯一約束名")
@DynamicInsert
動態(tài)插入,根據(jù)持久化對象的屬性是否有值明確生成insert語句。
@DynamicUpdate
動態(tài)修改,它會判斷持久化對象中屬性,哪些屬性值發(fā)生了改變就會生成update的語句。(持久化狀態(tài)下做修改)
@SelectBeforeUpdate
修改之前先查詢,查詢得到持久化對象再與脫管狀態(tài)下的對象進行比較,哪些屬性值發(fā)生了改變就會生成update的語句。(脫管狀態(tài)下做修改)
第二類
主鍵上
@Id
主鍵列
@GeneratedValue(strategy=GenerationType.AUTO)
指定了主鍵自增長策略
GenerationType.IDENTITY: 適宜MySQL、SqlServer有自增長列的數(shù)據(jù)庫。
GenerationType.SEQUENCE:適宜Oracle這種沒有自增長有sequence的數(shù)據(jù)庫。
GenerationType.AUTO:讓Hibernate根據(jù)數(shù)據(jù)庫方言自動選擇主鍵生成策略。
GenerationType.TABLE: 適宜所有的數(shù)據(jù)庫,因為它會單獨生成一張表來維護主鍵生成。
@Embedded
復合主鍵
@AttributeOverrides
指定復合主鍵中的列表
@AttributeOverrides({@AttributeOverride(name="firstName", column=@Column(name="F_NAME")),@AttributeOverride(name="lastName", column=@Column(name="L_NAME"))})
第三類
普通屬性上
@Column
持久化類中屬性轉(zhuǎn)化成數(shù)據(jù)庫表中列的相關信息
name:指定列名。
length: 該列支持的長度。
precision:有效的總位數(shù)。(BigDecimal類型才有效)
scale:小數(shù)點的位數(shù)。(BigDecimal類型才有效)
unique: 唯一約束。
nullable:非空約束。
insertable:是否允許插入true:允許 false: 不允許。
updatable:是否允許修改true:允許 false: 不允許。
columnDefinition :指定列的定義。columnDefinition="int(11) not null default 20"
@Lob
映射大的二進制數(shù)或者文本
@Temporal
修飾日期類型Date
TemporalType.DATE : yyyy-MM-dd
TemporalType.TIME : HH:mm:ss
TemporalType.TIMESTAMP : yyyy-MM-dd HH:mm:ss
@Transient
指定不是持久化屬性
transient關鍵字修飾不需要序列化的屬性,同時用它也能指定不是持久化的屬性。
第四類
集合屬性上(List/Set/Map/Array)
當持久化中有一個屬性是集合(Set、List、Map).
集合屬性會單獨生成一張表
定義集合屬性時面向接口,并且集合屬性需要程序員自己初始化
private List<String> list = new ArrayList<String>();
@ElementCollection
指定加載策略/指定集合中的元素類型
@ElementCollection(fetch=FetchType.LAZY,targetClass=String.class)
fetch=FetchType.EAGER: 立即加載 / fetch=FetchType.LAZY: 延遲加載
targetClass 集合中元素的類型
@CollectionTable
指定集合的表名
@CollectionTable(name="info")
List集合(有序集合)
@OrderColumn
指定排序列
@OrderColumn(name="o_id")
@Embeddable
說明此類是集合中的元素
Set集合(無序集合)
@Embeddable
注意:
Set集合生成表默認是沒有主鍵列的。如果想要生成主鍵列,需要為Set集合的元素類的屬性上添加非空約束!
@Column(nullable:false)
Set集合生成表的主鍵列:【外鍵列 + Set集合的元素列】
Map集合(有Map的key)
@MapKeyColumn
@Embeddable
注意
Map集合生成表的主鍵列:【外鍵列 + Map的Key】
第五類
關聯(lián)映射
單向關聯(lián)
一對一
//學生表中增加一個關聯(lián)id
@OneToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)
@JoinColumn(name="t_id",referencedColumnName="id")
private Teacher teacher;
一對多
//學生表中增加一個關聯(lián)id
@OneToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher")//延遲加載,指定關聯(lián)的持久化類,指定哪些維護關聯(lián)關系
@JoinColumn(name="t_id",referencedColumnName="id")
private Set<Student> students = new HashSet<Student>();
多對一
//學生表中增加一個關聯(lián)id
@ManyToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)
@JoinColumn(name="t_id",referencedColumnName="id")
private Set<Student> students = new HashSet<Student>();
多對多
@ManyToMany(fetch=FetchType.LAZY,targetEntity=Teacher.class)
@JoinTable(name="t_tea_stu",joinColumns=@JoinColumn(name="s_id",referencedColumnName="id"),inverseJoinColumns=@JoinColumn(name="t_id",referencedColumnName="id"))
private Set<Teacher> teachers = new HashSet<Teacher>();
雙向關聯(lián)
一對一
注解:@OneToOne
@OneToOne(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher")
private Student student;
@OneToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)
@JoinColumn(name="t_id",referencedColumnName="id",unique=true)
private Teacher teacher;
一對多
一端(主表):@OneToMany
@OneToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher")//延遲加載,指定關聯(lián)的持久化類,指定哪些維護關聯(lián)關系
private Set<Student> students = new HashSet<Student>();
多端(從表):@ManyToOne
生成外鍵列
@ManyToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)//延遲加載,指定關聯(lián)的持久化類
@JoinColumn(name="t_id",referencedColumnName="id",foreignKey=@ForeignKey(name="fk_tea_stu"))//生成外鍵列t_id,關聯(lián)Teacher類中的id
private Teacher teacher;
保存主表,再保存從表
級聯(lián)級別
@OneToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher",cascade=CascadeType.REMOVE,orphanRemoval=true)
CascadeType.REMOVE 級聯(lián)刪除
orphanRemoval=true 刪除孤兒記錄
在不刪除老師的基礎上,把學生刪除
以后千萬不要配置@ManyToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class,cascade=CascadeType.REMOVE)
CascadeType.REMOVE 級聯(lián)刪除,以后千萬不要配置
多對多
注解
@ManyToMany
生成中間表來維護關聯(lián)關系
用Set集合定義關聯(lián)屬性, set集合中的元素是關聯(lián)的持久化類
@ManyToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teachers")
private Set<Student> students = new HashSet<Student>();
@ManyToMany(fetch=FetchType.LAZY,targetEntity=Teacher.class)
@JoinTable(name="t_tea_stu",joinColumns=@JoinColumn(name="s_id",referencedColumnName="id"),inverseJoinColumns=@JoinColumn(name="t_id",referencedColumnName="id"))
private Set<Teacher> teachers = new HashSet<Teacher>();
第六類
繼承映射
第一種方式(SINGLE_TABLE):所有子類中屬性都生成到父類表中(一張表)
@Entity @Table(name="parent")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="DC", discriminatorType=DiscriminatorType.INTEGER)// 辨別者列
@DiscriminatorValue("1") // 辨別者列值
public class Person{}
//子類
@Entity
@DiscriminatorValue("2") // 辨別者列值
public class Teacher{}
注意:
所有子類屬性中不能加非空約束
第二種方式(JOINED):所有的子類與父類都會單獨生成表(子類表的中主鍵列同時也是外鍵列,它引用頂級父類表中的主鍵列).
@Entity @Table(name="parent")
@Inheritance(strategy=InheritanceType.JOINED)
public class Person{}
//子類
@Entity @Table(name="teacher")
public class Teacher{}
注意:查詢時會出現(xiàn)很多join語句
第三種方式(TABLE_PER_CLASS):所有的子類與父類都會單獨生成表,子類會把父類中的屬性繼承過來生成在自己的表中。
@Entity @Table(name="parent")
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Person{}
//子類
@Entity @Table(name="teacher")
public class Teacher{}
注意:
這種策略主鍵不能用自增長
查詢時會出現(xiàn)union運算
映射文件說明
hibernate-mapping 根元素
package
指定包名,如果沒有指定,本文件出現(xiàn)的所有實體類必須帶上完整包名.如果指定,就可以不帶完整包名。
auto-import
默認為true 自動導入,在進行hql查詢的時候不用寫包名!
如果設置為false,在hql查詢的時候需要指定包名,如:session.createQuery("from cn.itcast.entity.User");
schema
庫名
class 類映射一個表
name 類名,是否指定完整路徑看package
table 表名
id 主鍵映射
name 屬性名
column 表字段名,不寫也可以
generator 主鍵策略
native 自增長(根據(jù)底層數(shù)據(jù)庫的能力選擇 identity、sequence )
identity MySql中自增長的方式
sequence Oracle中以序列的方式實現(xiàn)自增長!
increment 也是自增長但不能處理并發(fā)問題!
assigned 手動指定主鍵的值
uuid uuid值作為主鍵
foreign 外鍵策略(一對一映射時候用到)
property 其它字段映射
name 屬性名
column 表字段名,不寫也可以。如果字段是數(shù)據(jù)的關鍵字使用反引號 `desc`
length 指定字符類型的長度,默認255
type 指定字段類型
hibernate支持的類型默認都是小寫
string/java.lang.String
date/timestamp/ 如果屬性是java.util.Date類型,字段映射沒有指定類型,默認是datetime類型
unique
唯一約束
not-null
不能為空約束
代碼方式建表
加載hibernate.cfg.xml
Configuration cfg = new Configuration().configure();
工具類
SchemaExport export = new SchemaExport(cfg);
建表-參數(shù)1:是否打印生成的sql到控制臺-參數(shù)2:是否執(zhí)行生成的sql
export.create(true, true);
查詢方式
get主鍵查詢
User user = (User) session.get(User.class, 1);
立即從數(shù)據(jù)庫表中查詢數(shù)據(jù)
load對象導航查詢(懶加載查詢)
user = (User) session.load(User.class, 1);
延遲從數(shù)據(jù)庫表查詢數(shù)據(jù),一開始返回一個代理對象,當真正用到屬性的時候,再到數(shù)據(jù)庫表中查詢
注意:用它時保證session不要被關閉
Hql查詢
Hibernate Query Language
Hibernate查詢語句
步驟:
獲得Session
寫hql語句
查詢數(shù)據(jù)庫獲得Query對象
如果有占位符,就需要對占位符賦值 query.setParameter();
如果需要分頁limit賦值 query.setFirstResult(start); query.setMaxResults(size);
獲取查詢查詢結(jié)果
如果本次查詢有多條記錄返回:query.list();
如果本次查詢只有一條記錄返回:query.uniqueResult();
from字句
List<Student> students = session.createQuery("from Student").list();
List<Student> students = session.createQuery("from Student as stu").list();
List<Student> students = session.createQuery("from Student stu").list();
User user =(User) session.createQuery("from User where id=1").uniqueResult();
select字句
List<Student> students = session.createQuery("select s from Student as s").list();
List<String> names = session.createQuery("select s.name from Student s").list();
List<Object[]> lists = session.createQuery("select s.name,s.age from Student s").list();
List<Object[]> lists = session.createQuery("select name,age from Student").list();
分頁
Query query = session.createQuery("select s from Student s");
query.setFirstResult(0);
query.setMaxResults(5);
List<Student> students = query.list();
select new 字句
可以改變List集合中存放什么
List<Map<String,Object>> list = session.createQuery("select new map(s.name,s.age) from Student s").list();
List<List<Object>> list = session.createQuery("select new list(s.name,s.age) from Student s").list();
List<User> list = session.createQuery("select new com.shuai.domain.User(name,age) from Student").list();
關聯(lián)(持久化類)與連接(數(shù)據(jù)庫表)
隱式關聯(lián)(不需要寫join語句)
查詢時,關聯(lián)的屬性是一個持久化類。
List<Student> students = session.createQuery("select s from Student s where s.teacher.id=?").setParameter(0,1).list();
顯示關聯(lián)(需要寫join語句)
查詢時,關聯(lián)屬性是一個Set集合
Teacher t = (Teacher)session.createQuery("select t from Teacher t inner join t.students where t.students.id=?").setParameter(1,1).uniqueResult();
抓取連接(查詢延遲的屬性)
查詢時,關聯(lián)屬性配置了延遲加載的,但本次查詢要查詢出來 join fetch關聯(lián)的屬性
List<Student> students = session.createQuery("select s from Student s join fetch s.teacher").list();
排序 order by
List<Student> students = session.createQuery("select s from Student s order by s.age asc").list();
分組 group by
List<Object[]> list = session.createQuery("select count(s),s.teacher.name from Student s group by s.teacher.name").list();
分組過濾 having
List<Object[]> list = session.createQuery("select count(s),avg(s.score),sum(s.score),s.teacher.name from Student s group by s.teacher.name having s.teacher.id=?").setParameter(0,1).list();
聚合函數(shù) count/sum/max/min/avg
count
Long count = (Long)session.createQuery("select count(*) from Student").uniqueResult();
sum
Double sum = (Double)session.createQuery("select sum(score) from Student").uniqueResult();
max
Float max = (Float)session.createQuery("select max(score) from Student").uniqueResult();
min
Float min = (Float)session.createQuery("select min(score) from Student").uniqueResult();
avg
Float avg = (Float)session.createQuery("select avg(score) from Student").uniqueResult();
where字句部分(查詢過濾部分)
Hibernate的where子句部分能支持的運算符,表達式、函數(shù)特別多,用法與sql語句是一樣的
常用的表達式、運算符、函數(shù)
=、<、<=、>、>=、!=、and、or、distinct、between...and 、like、concat()、is null, is not null, is empty, is not empty、second(...),minute(...), hour(...), day(...), month(...)
支持EJB-QL 3.0的函數(shù)
trim(), lower(), upper(), length(), abs(), sqrt(), bit_length(), mod()
支持操作集合屬性的函數(shù)
size()|size, minelement(), maxelement(), minindex(), maxindex()
使用
List<Student> students = session.createQuery("select s from Student s where s.name like ?8").setParameter("9","%小%").list();
List<Student> students = session.createQuery("select s from Student s where s.name like concat('%',?2,"%")").setParameter("2","小").list();
List<Student> students = session.createQuery("select s from Student s where s.name is not null").list();
List<Student> students = session.createQuery("select s from Student s where trim(s.name) like ?").setParameter(0,"%帥%").list();
List<Student> students = session.createQuery("select s from Student s where length(s.name) = ?").setParameter(0,"%帥%").list();
List<Student> students = session.createQuery("select s from Student s where sqrt(s.id)=?").setParameter(0,1.0d).list();
List<Student> students = session.createQuery("select s from Student s where bit_length(s.name)=?").setParameter(0,32L).list();
List<Student> students = session.createQuery("select s from Student s where mod(s.id,?)=?").setParameter(0,2).setParameter(1,0).list();
List<Order> orders = session.createQuery("select o from Order o where size(o.orderItems) =?").setParameter(0,3).list();
List<Order> orders = session.createQuery("select o from Order o where minelement(o.orderItems) =?").setParameter(0,100).list();
List<Order> orders = session.createQuery("select o from Order o where maxelement(o.orderItems) =?").setParameter(0,100).list();
List<Order> orders = session.createQuery("select o from Order o where maxindex(o.orderItems) =?").setParameter(0,1).list();
List<Order> orders = session.createQuery("select o from Order o where minindex(o.orderItems) =?").setParameter(0,1).list();
子查詢
hibernate的子查詢與SQL語句的中子查詢一樣,子查詢部分放在in、not in里面
使用
List<Student> students = session.createQuery("select s from Student as s where s.id in(select t.id from Teacher t)").list();
多態(tài)查詢
當你的持久化類存在繼承關系時,你查詢父類時,它會把父類所有的對象查詢出來,而且也會把所有子類對象查詢出來。
使用
List<Object> lists = session.createQuery("from java.lang.Object").list();
命名查詢
把所有hql語句寫在一個單獨的配置文件中
一般在實際的項目中用得比較多,它會把比較復雜的hql語句寫在一個單獨的配置文件中
方便以后對hql語句進行優(yōu)化,也方便統(tǒng)一管理
第一種方式
1.創(chuàng)建xxx.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<query name="hql_1">select s from Student s where s.name like ?</query>
</hibernate-mapping>
2.在hibernate.cfg.xml文件中配置xxx.hbm.xml
<mapping resource="com/shuai/domain/xxx.hbm.xml"/>
3.使用
List<Student> students = session.getNamedQuery("hql_1").setParameter(0, "%小%").list();
第二種方式
1.在持久化類上加注解
@NamedQuery(name="hql_1", query="select s from Student s where s.name like ?");
public class Student{}
2.使用
List<Student> students = session.getNamedQuery("hql_1").setParameter(0, "%小%").list();
Criteria查詢
說明
完全面向?qū)ο蟮?,不需要寫任可查詢語句
查詢步驟
1.獲取Session
2.Criteria criteria = session.createCriteria(持久化類)
3.如果需要分頁查詢就需要為limit ?,? 這兩個問號賦值
第一個問號:criteria.setFirstResult(start);
第二個問號:criteria.setMaxResults(size);
4.獲取查詢查詢結(jié)果
如果本次查詢有多條記錄返回:criteria.list();
如果本次查詢只有一條記錄返回:criteria.uniqueResult();
API
add(Criterion criterion)
添加查詢條件.Criterion : 代表一個查詢條件.
Restrictions 工具類,專門負責生成查詢條件對象,它把where部分都改成了靜態(tài)方法。
Property工具類,專門負責生成查詢條件對象.
addOrder(Order order)
添加排序
Order.asc("屬性名") | Order.desc("屬性名")
Property.forName("age").asc()|Property.forName("age").desc()
setProjection(Projection projection)
查詢哪些列
createAlias(String associationPath, String alias)
創(chuàng)建關聯(lián)查詢
用它創(chuàng)建出來的關聯(lián)查詢,添加查詢條件時,如果不加別名,它是為目標持久類添加查詢條件.
createCriteria(String associationPath)
創(chuàng)建關聯(lián)查詢
用它創(chuàng)建出來的關聯(lián)查詢,添加查詢條件時,它是為關聯(lián)的持久化類添加查詢條件.
setFetchMode(String associationPath, FetchMode mode)
抓取連接(join fetch)
FetchMode: 抓取模式
FetchMode.JOIN FetchMode.EAGER 立即查詢
FetchMode.SELECT FetchMode.LAZY 延遲查詢
DetachedCriteria.
離線查詢
用它就可以定義一條查詢語句.
用得時候需要與Session關聯(lián)起來.
離線查詢的主要作用就是為了做子查詢. in 、not in(離線查詢對象)
使用
List<Student> students = session.createCriteria(Student.class).list();
List<Student> students = session.createCriteria("com.shuai.domain.Student").list();
List<Student> students = session.createCriteria(Student.class).add(Restrictions.like("name","%帥%")).list();
List<Student> students = session.createCriteria(Student.class).add(Restrictions.like("name","%帥%")).add(Restrictions.between("age",20,30)).list();
List<Student> students = session.createCriteria(Student.class).add(Property.forName("name").like("%帥%")).list();
List<Student> students = session.createCriteria(Student.class).add(Property.forName("age").between(20,30)).list();
List<Student> students = session.createCriteria(Student.class).add(Restrictions.sqlRestriction("length(name)=4")).list();
List<Student> students = session.createCriteria(Student.class).addOrder(Order.asc("age")).list();
List<Student> students = session.createCriteria(Student.class).addOrder(Property.forName("age").asc()).list();
List<String> names = session.createCriteria(Student.class).setProjection(Projections.property("name")).list();
ProjectionList pl = Projections.projectionList();
pl.add(Projections.property("name"));
pl.add(Projections.property("age"));
List<Object[]> names = session.createCriteria(Student.class).setProjection(pl).list();
Object res = session.createCriteria(Student.class).setProjection(Projections.rowCount()).uniqueResult();
Object res = session.createCriteria(Student.class).setProjection(Projections.avg("score")).uniqueResult();
Object res = session.createCriteria(Student.class).setProjection(Projections.max("score")).uniqueResult();
List<Object[]> lists = session.createCriteria(Student.class).setProjection(Projections.projectionList().add(Projections.rowCount()).add(Projections.property("teacher.id")).add(Projections.groupProperty("teacher.id"))).list();
List<Student> students = session.createCriteria(Student.class).createAlias("teacher","t").add(Restrictions.eq("t.id",1)).list();
List<Student> students = session.createCriteria(Student.class).createCriteria("teacher").add(Restrictions.eq("t.id",1)).list();
List<Student> students = session.createCriteria(Student.class).createAlias("teacher","t").add(Restrictions.gt("age",100)).add(Restrictions.eq("t.id",1)).list();
List<Student> students = session.createCriteria(Student.class).add(Restrictions.gt("age",100)).createCriteria("teacher").add(Restrictions.eq("id",1)).list();
List<Student> students = session.createCriteria(Student.class).setFetchMode("teacher",FetchMode.JOIN).list();
DetachedCriteria dc = DetachedCriteria.forClass(Student.class);
List<Student> students = dc.getExecutableCriteria(session).list();
DetachedCriteria dc = DetachedCriteria.forClass(Teacher.class);
dc.setProjection(Projections.property("id"));
List<Student> students = session.createCriteria(Student.class).add(Property.forName("id").in(dc)).list();
本地sql查詢
說明
Native Sql Query原生的sql查詢
要求寫sql語句
SQLQuery 是 Query的子類
步驟
1.獲取Session
2.寫sql語句
3.SQLQuery sqlquery = session.createSQLQuery(sql);
4.如果hql語句中有占位符,就需要為占位符賦值. sqlquery.setParameter("索引號", "值");
如果需要分頁查詢就需要為limit ?,? 這兩個問號賦值
第一個問號:sqlquery.setFirstResult((pageIndex - 1) * pageSize);
第二個問號:sqlquery.setMaxResults(pageSize);
5.獲取查詢查詢結(jié)果
如果本次查詢有多條記錄返回:sqlquery.list();
如果本次查詢只有一條記錄返回:sqlquery.uniqueResult();
API
addEntity(Class entityType)
實體查詢
addScalar(String columnAlias)
標量查詢
addJoin(String tableAlias, String path)
關聯(lián)查詢
使用
List<Student> students = session.createSQLQuery("select * from student").addEntity(Student.class).list();
List<Student> students = session.createSQLQuery("select * from student").addEntity("com.shuai.domain.Student").list();
List<Object[]> lists = session.createSQLQuery("select s.name,s.age from student as s").list();
List<Object[]> lists = session.createSQLQuery("select * from student as s").addScalar("s.name").addScalar("s.age").list();
List<Object[]> lists = session.createSQLQuery("select s.*,t.* from student s,teacher t where s.id = t.id").addEntity("s",Student.class).addEntity("t",Teacher.class).addJoin("t","s.teacher").addScalar("s.name").list();
命名查詢
第一種方式
用xxx.hbm.xml
步驟
1.提供一個配置文件(xxx.hbm.xml)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<sql-query name="sql_1">
SELECT s.*,t.* FROM stu_info AS s, tea_info AS t WHERE s.t_id = t.tea_id
<!-- addEntity: 實體查詢 -->
<return alias="s" class="com.shuai.domain.Student"></return>
<return alias="t" entity-name="com.shuai.domain.Teacher"></return>
<!-- addJoin : 關聯(lián)查詢 -->
<return-join alias="t" property="s.teacher"></return-join>
<!-- addScalar : 標量查詢 -->
<return-scalar column="s.stu_name"/>
</sql-query>
<sql-query name="call_proc">
{call query_stu(?)}
<return class="com.shuai.domain.Student"></return>
</sql-query>
</hibernate-mapping>
2.在hibernate.cfg.xml文件中配置xxx.hbm.xml
<mapping resource="com/shuai/domain/Query.hbm.xml"/>
3.使用
List<Object[]> lists = session.getNamedQuery("sql_1").list();
第二種方式
在持久化類上加注解
步驟
1.在實體類上加注解
@NamedNativeQuery(name="sql_2", resultSetMapping="rs", query="SELECT s.*,t.* FROM stu_info AS s, tea_info AS t WHERE s.t_id = t.tea_id")
@SqlResultSetMapping(name="rs", entities={@EntityResult(entityClass=Student.class), // 實體查詢
@EntityResult(entityClass=Teacher.class)},
columns={@ColumnResult(name="s.stu_name")}) // 標量要詢
public class Student{}
2.使用
List<Object[]> lists = session.getNamedQuery("sql_2").list();
List<Student> lists = session.getNamedQuery("call_proc").setParameter(0, 20).list();
Hibernate調(diào)用存儲過程
第一種方式:用命名查詢的方法
List<Student> lists = session.getNamedQuery("call_proc").setParameter(0, 20).list();
第二種方式:直接用session.createSQLQuery()調(diào)用.
List<Student> lists = session.createSQLQuery("{call query_stu(?)}").addEntity(Student.class).setParameter(0, 20).list();
hibernate批處理
概述
如果有10w條數(shù)據(jù)需要一次性插入到數(shù)據(jù)庫表.這個時候用Hibernate做添加的話有可能會出現(xiàn)內(nèi)存溢出
批量添加
for(int i = 0; i < 100000; i++){
Teacher t = new Teacher();
session.save(t);
// t : 持久化狀態(tài),持久化狀態(tài)的對象是放在Session的一級緩存中,因為一級緩存是放在內(nèi)存中.(10w對象存放在內(nèi)存中)
// 當一級緩存中的對象達到一定數(shù)量,那就把一級緩存中的對象同步到底層的數(shù)據(jù)庫,再清空一級緩存,釋放內(nèi)存
if (i % 10 == 0){
// 把一級緩存中的對象同步到底層的數(shù)據(jù)庫
session.flush();
// 清空一級緩存,釋放內(nèi)存
session.clear();
}
}
session.commit();
批量修改
for (int i = 1; i <= 100000; i++){
// t : 持久化狀態(tài),持久化狀態(tài)的對象是放在Session的一級緩存中,因為一級緩存是放在內(nèi)存中.(10w對象存放在內(nèi)存中)
Teacher t = (Teacher)session.get(Teacher.class, i);
t.setAge(28);
// 當一級緩存中的對象達到一定數(shù)量,那就把一級緩存中的對象同步到底層的數(shù)據(jù)庫,再清空一級緩存,釋放內(nèi)存
if (i % 10 == 0){
// 把一級緩存中的對象同步到底層的數(shù)據(jù)庫
session.flush();
// 清空一級緩存,釋放內(nèi)存
session.clear();
}
}
session.commit();
批量刪除
for (int i = 1; i <= 100000; i++){
// t : 持久化狀態(tài),持久化狀態(tài)的對象是放在Session的一級緩存中,因為一級緩存是放在內(nèi)存中.(10w對象存放在內(nèi)存中)
Teacher t = (Teacher)session.get(Teacher.class, i);
session.delete(t);
// 當一級緩存中的對象達到一定數(shù)量,那就把一級緩存中的對象同步到底層的數(shù)據(jù)庫,再清空一級緩存,釋放內(nèi)存
if (i % 10 == 0){
// 把一級緩存中的對象同步到底層的數(shù)據(jù)庫
session.flush();
// 清空一級緩存,釋放內(nèi)存
session.clear();
}
}
session.commit();
DML風格的HQL語句
概述
DML : Data Manipulation Language (DML) the statements: INSERT, UPDATE, DELETE
語法 :( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?.
操作DML風格HQL的步驟
獲取Session
寫DML風格的hql語句
Query query = session.createQuery(hql);
如果hql語句中有占位符需要設置參數(shù)值: query.setParameter(i, "值").
int res = query.executeUpdate();
使用
全部修改
String sql = "update from Teacher set age = ?";
int res = session.createQuery(sql).setParameter(0,20).executeUpdate();
條件修改
String sql = "update from Teacher set age = ? where id < ?";
int res = session.createQuery(sql).setParameter(0,20).setParameter(1,100).executeUpdate();
條件刪除
String sql = "delete from Teacher t where t.age = ?";
int res = session.createQuery(sql).setParameter(0,40).executeUpdate();
hibernate數(shù)據(jù)過濾
概述
當你做查詢時,有一個查詢條件永遠是固定的
使用數(shù)據(jù)過濾的步驟
1.定義數(shù)據(jù)過濾
@FilterDef()
2.指定哪些持久類使用該數(shù)據(jù)過濾
@Filter()
3.開啟該數(shù)據(jù)過濾
session.enableFilter("數(shù)據(jù)過濾的名稱").setParameter("定義的過濾字段名稱",過濾字段的值);
使用
1.
@FilterDef(name="ageFilter", parameters={@ParamDef(name="minAge", type="int")})
public class Teacher{}
2.
@Filter(name="ageFilter", condition="age > :minAge")
public class Student{}
3.
session.enableFilter("ageFilter").setParameter("minAge", 20);
List<Student> students = session.createQuery("select t from Student t").list();
hibernate連接池
支持c3p0.
使用時配置hibernate.cfg.xml
<property name="hibernate.c3p0.min_size">3</property>
最小連接數(shù)
<property name="hibernate.c3p0.max_size">6</property>
最大連接數(shù)
<property name="hibernate.c3p0.max_statements">100</property>
一次執(zhí)行的最大sql命令的個數(shù)
<property name="hibernate.c3p0.acquire_increment">2</property>
連接不夠用一次增加多少個連接
<property name="hibernate.c3p0.timeout">5000</property>
連接超時時間
<property name="hibernate.c3p0.idle_test_period">3000</property>
連接空閑測試時間
hibernate緩存
為什么使用緩存
減少數(shù)據(jù)庫訪問次數(shù),提高程序運行效率
一級緩存
session
緩存不共享,每個session維護自己獨立的緩存區(qū),session關閉后,緩存銷毀
特點:緩存時間短范圍小,效果不太明顯.
跟Session相關(存放在內(nèi)存中)
默認是開啟的
作用:提高CUD操作的性能
操作
boolean contains(Object object)
判斷Session的一級緩存中是否包含一個對象,包含的話這個對象就是持久化狀態(tài)。
void evict(Object object)
從Session的一級緩存中逐出一個對象.(該對象就不是持久化狀態(tài)的對象).
void flush()
將Session的一級緩存中的對象,同步到底層數(shù)據(jù)庫表中.(立即同步)
void clear()
清空Session的一級緩存,所有的持久化狀態(tài)的對象都清空。(釋放內(nèi)存)
void close()
關閉Session,先調(diào)用flush(),再調(diào)用clear().
二級緩存
基于sessionFactory的緩存
二級緩存的內(nèi)容,可以給多個session訪問,二級緩存數(shù)據(jù)可以給所有的session共享.
跟SessionFactory相關,因為SessionFactory存活的時間長。
默認是關閉的.
作用:提高查詢效率.
特點:緩存資源,整個應用程序都可以使用.范圍比較大.
使用二級緩存:
1.需要指定哪些類需要放入二級緩存區(qū)域
2.放入緩存的數(shù)據(jù),要符合這樣的特點,不要經(jīng)常修改
hibernate的二級緩存是以插件的形式提供給開發(fā)程序員使用的,且有已經(jīng)實現(xiàn)好的插件.
用的時候直接引入即可(hibernate.cfg.xml)配置.
二級緩存中的對象存放到哪里,這個需要配置.
一般會配置內(nèi)存中存放一些對象,超出了內(nèi)存中放存的對象個數(shù),就寫入磁盤.
ehcache.xml (配置二級緩存對象存放的配置文件).
HashtableCacheProvider使用步驟:
1.hibernate.cfg.xml配置開啟二級緩存
<property name="hibernate.cache.use_second_level_cache">true</property>
2.hibernate.cfg.xml配置使用哪個二級緩存框架
<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
3.配置指定哪些類加入緩存
第一種配置hibernate.cfg.xml
<class-cache usage="read-write" class="cn.shuai.domain.User"/>
read-only/read-write
第二種配置User.hbm.xml
<cache usage="read-write"/>
4.開啟對象中的集合緩存-注意集合中的對象也要加入緩存
<class-cache usage="read-write" class="cn.shuai.domain.Address"/>
<collection-cache usage="read-write" collection="cn.shuai.domain.User.addresses"/>
5.注意:
以上配置是對get查詢方式配置的.
6.如果需要對Hql查詢也可以讀取二級緩存,還需要配置
<property name="hibernate.cache.use_query_cache">true</property>
7.并且使用HQL查詢時寫法要注意
User user =(User) session.createQuery("from User where id=1").setCacheable(true);//數(shù)據(jù)要加入二級緩存/數(shù)據(jù)從二級緩存中取
EhCacheRegionFactory使用
1.配置開啟二級緩存hibernate.cfg.xml文件中配置開啟二級緩存.
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
2.拷貝二級緩存需要的jar包
ehcache-core-2.4.3.jar、hibernate-ehcache-4.3.8.Final.jar、slf4j-api-1.7.2.jar、slf4j-jdk14-1.7.2.jar
3.拷貝ehcache.xml文件
<ehcache>
<diskStore path="F:\\ehcache"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="shuaiCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>
4.配置哪些持久化類用二級緩存
第一種方式:hibernate.cfg.xml文件中配置
<class-cache usage="read-write" class="com.shuai.domain.Teacher" region="shuaiCache"/>
第二種方式:注解配置
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE,region="shuaiCache")
5.操作二級緩存的方法
Cache cache = SessionFactory.getCache();
獲取緩存對象
boolean containsEntity(Class entityClass, Serializable identifier)
判斷二級緩存中在是否包含一個對象
boolean containsEntity(String entityName, Serializable identifier)
void evictAllRegions();
清空二級緩存中所有對象
void evictEntity(Class entityClass, Serializable identifier)
從二級緩存中踢出指定的對象
void evictEntity(String entityName, Serializable identifier)
void evictEntityRegion(Class entityClass)
從二級緩存中踢出指定類型所有的對象
void evictEntityRegion(String entityName)
6.查詢緩存(緩存的是查詢語句)
7.獲取二級緩存的統(tǒng)計信息
1.配置生成統(tǒng)計信息(hibernate.cfg.xml)
<property name="hibernate.generate_statistics">true</property>
<property name="hibernate.cache.use_structured_entries">true</property>
2.獲取統(tǒng)計信息
Statistics statistics = sessionFactory.getStatistics();
命中的數(shù)量:statistics.getSecondLevelCacheHitCount()
錯失的數(shù)量:statistics.getSecondLevelCacheMissCount()
8.對象在二級緩存中用什么格式保存
Map集合
key:主鍵列的值
value:緩存對象,該對象對需要緩存的對象中的數(shù)據(jù)做了封裝.
SecondLevelCacheStatistics scs = statistics.getSecondLevelCacheStatistics("com.shuai.domain.Student");
scs.getEntries();
查詢緩存(緩存的是查詢語句)
概述
默認也是關閉的
它是在二級緩存的基礎之上
使用步驟
1.配置開啟查詢緩存(hibernate.cfg.xml)
<property name="hibernate.cache.use_query_cache">true</property>
2.在創(chuàng)建查詢時需要設置是否緩存這條語句.
query.setCacheable(true);
List<Student> students = session.createQuery("select s from Student s join fetch s.teacher").setCacheable(true).list();
查詢緩存的緩存數(shù)據(jù)格式
{"sql語句" : {"org.fkjava.hibernate.domain.Student" : [1,2,3,4,5,6],"org.fkjava.hibernate.domain.Teacher" : [1,2]}}
注意:它要求hql語句要一致,而且hql語句中的占位符賦值也要一致,才能命中!
Session的線程安全問題
概述
如果是Hibernate3.1之前版本,它提供了HibernateUtil工具類可以獲取當前線程相關的Session.
如果是Hibernate3.1之后版本,它提供了可配置的方式,讓我們把Session配置成線程相關的Session.
把Session配置成線程安全
在hibernate.cfg.xml中配置
<property name="hibernate.current_session_context_class">jta|thread</property>
org.hibernate.context.internal.JTASessionContext : jta (全局事務)
org.hibernate.context.internal.ThreadLocalSessionContext : thread (jdbc事務)
使用
Session session = session.getCurrentSession();
注意:
不要調(diào)用session.close();
面向JPA編程
Hibernate4編程
Configuration
SessionFactory
Session
Transaction
Query query = session.createQuery(hql);
Criteria criteria = session.createCriteria();
SQLQuery sqlquery = session.createSQLQuery(sql);
src/hibernate.cfg.xml
JPA編程
Persistence
EntityManagerFactory
EntityManager
EntityTransaction
Query query = entityManager.createQuery(jpql);
Query query = entityManager.createQuery(CriteriaQuery);
Query query = entityManager.createNativeQuery(sql);
src/META-INF/persistence.xml
JPQL
Java Persistence Query Language
java持久化查詢語言.
web項目引入jpa
1.創(chuàng)建JPA項目
new --> jpa --> jpa project --> jpa fact(jpa implementation type:disable library configuration)
需要項目src中的META-INF文件夾和文件夾中的persistence.xml
把這個文件夾拷貝到我們自己的web項目的src目錄即可。
2.修改persistence.xml
在hibernate-entitymanager-xxx.jar/org.hibernate.jpa/persistence_2_1.xsd文件中拷貝文件頭即可
<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>
3.配置持久化單元persistence-unit
<persistence-unit name="shuaijpa" transaction-type="RESOURCE_LOCAL">
</persistence-unit>
name : 持久化單元名稱
transaction-type : JTA|RESOURCE_LOCAL事務
4.配置JPA的提供商(實現(xiàn)商)
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
5.配置持久化類
<class>com.shuai.domain.Teacher</class>
6.配置屬性
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/hibernate"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="32147"/>
<property name="hibernate.c3p0.max_size" value="10"/>
<property name="hibernate.c3p0.min_size" value="2"/>
</properties>
7.使用
public void oneTest(){
// 第一步:創(chuàng)建EntityManagerFactory
EntityManagerFactory emf = Persistence.createEntityManagerFactory("shuaijpa");
// 第二步:創(chuàng)建EntityManager
EntityManager em = emf.createEntityManager();
// 第三步:獲取事務
EntityTransaction transaction = em.getTransaction();
// 第四步:開啟事務
transaction.begin();
// 第五步:利用 EntityManager完成所有的持久化操作
Teacher t = new Teacher();
t.setName("帥哥");
t.setDept("開發(fā)部");
t.setAge(30);
em.persist(t);
// 第七步:事務提交或回滾
transaction.commit();
// 第八步:關閉EntityManager與EntityManagerFactory
em.close();
emf.close();
}
增加
第一種方式
Teacher t = new Teacher(); // 瞬態(tài)
t.setAge(20);
t.setName("帥哥");
t.setDept("開發(fā)部");
t.setJob("項目經(jīng)理");
em.persist(t); // 持久化狀態(tài)
System.out.println(em.contains(t)); // 判斷一個對象是不是持久化狀態(tài)
第二種方式
Teacher t = new Teacher(); // 瞬態(tài)
t.setAge(20);
t.setName("帥哥");
t.setDept("開發(fā)部");
t.setJob("項目經(jīng)理");
Teacher t1 = em.merge(t); // t1 持久化狀態(tài)
System.out.println(em.contains(t1));
刪除
Teacher t = em.find(Teacher.class, 4); // t 持久化狀態(tài)
em.remove(t);
修改
持久化狀態(tài)下
Teacher t = em.find(Teacher.class, 1); // t 持久化狀態(tài)
t.setAge(300);
脫管狀態(tài)下
Teacher t = new Teacher();
t.setId(1);
t.setAge(100);
t.setName("admin");
em.merge(t);
查詢
Teacher t = em.find(Teacher.class, 1); // t 持久化狀態(tài)
System.out.println(em.contains(t)); // 判斷一個對象是不是持久化狀態(tài)
操作一級緩存中的方法
boolean contains(Object object)
判斷EntityManager的一級緩存中是否包含一個對象,包含的話這個對象就是持久化狀態(tài)。
void detach(Object object)
從EntityManager的一級緩存中逐出一個對象.(該對象就不是持久化狀態(tài)的對象).
void flush()
將EntityManager的一級緩存中的對象,同步到底層數(shù)據(jù)庫表中.(立即同步)
void clear()
清空EntityManager的一級緩存,所有的持久化狀態(tài)的對象都清空。(釋放內(nèi)存)
void close()
關閉EntityManager,先調(diào)用flush(),再調(diào)用clear().
三套查詢
第一套查詢(JPQL查詢)
查詢步驟
1.獲取EntityManager
2.寫jpql語句
3.Query query = entityManager.createQuery(jpql);
4.如果hql語句中有占位符,就需要為占位符賦值. query.setParameter("索引號", "值");
如果需要分頁查詢就需要為limit ?,? 這兩個問號賦值
第一個問號:query.setFirstResult(start);
第二個問號:query.setMaxResults(size);
5.獲取查詢查詢結(jié)果
如果本次查詢有多條記錄返回:query.getResultList();
如果本次查詢只有一條記錄返回:query.getsingleResult();
使用
List<Student> lists = em.createQuery("select s from Student as s", Student.class).getResultList();
List<Student> lists = em.createQuery("from Student", Student.class).getResultList();
List<Map<String, Object>> lists = em.createQuery("select new map(name as name, age as age) from Student").getResultList();
List<Student> lists = em.createQuery("from Student", Student.class).setFirstResult(start).setMaxResults(size).getResultList();
命名查詢
@NamedQuery(name="query_1", query="select s from Student s join fetch s.teacher")
public class Teacher {}
List<Student> lists = em.createNamedQuery("query_1").getResultList();
第二套查詢(sql查詢)
查詢步驟
1.獲取EntityManager.
2.寫sql語句.
3.查詢
Query query = createNativeQuery(String sqlString); // 查詢多列
Query query = createNativeQuery(String sqlString, Class resultClass); // 實體查詢
Query query = createNativeQuery(String sqlString, String resultSetMapping); // 關聯(lián)查詢
4.如果hql語句中有占位符,就需要為占位符賦值. query.setParameter("索引號", "值");
如果需要分頁查詢就需要為limit ?,? 這兩個問號賦值
第一個問號:query.setFirstResult((pageIndex - 1) * pageSize);
第二個問號:query.setMaxResults(pageSize);
5.獲取查詢查詢結(jié)果:
如果本次查詢有多條記錄返回:query.getResultList();
如果本次查詢只有一條記錄返回:query.getsingleResult();
使用
List<Student> lists = em.createNativeQuery("select * from stu_info", Student.class).getResultList();
List<Object[]> lists = em.createNativeQuery("select * from stu_info").getResultList();
List<Object[]> lists = em.createNativeQuery("select s.*, t.* from stu_info as s, tea_info as t where s.t_id = t.tea_id", "rs").getResultList();
@SqlResultSetMapping(name="rs" , entities={@EntityResult(entityClass=Student.class),@EntityResult(entityClass=Teacher.class)},columns={@ColumnResult(name="s.stu_name")})
public class Student {}
第三套查詢(CriteriaQuery查詢)
查詢步驟
1.獲取EntityManager.
2.Query query = entityManager.createQuery(CriteriaQuery);
3.如果需要分頁查詢就需要為limit ?,? 這兩個問號賦值
第一個問號:query.setFirstResult(start);
第二個問號:query.setMaxResults(size);
4.獲取查詢查詢結(jié)果:
如果本次查詢有多條記錄返回:query.getResultList();
如果本次查詢只有一條記錄返回:query.getsingleResult();
API
CriteriaBuilder
構(gòu)建查詢對象的類.
構(gòu)建CriteriaQuery
生成查詢條件
生成排序
生成聚集函數(shù)
CriteriaQuery
查詢對象類
Root from(Class<X> entityClass) : 指定查詢哪個持久化類.
groupBy(Expression<?>... grouping) : 分組
multiselect(Selection<?>... selections) : 查詢多列
select(Selection<? extends T> selection) : 查詢一列
where(Predicate... restrictions) : 添加查詢條件
orderBy(Order... o): 排序
Root
對查詢的持久化類中的屬性做了封裝.
Path path = root.get("屬性名");
join() : 關聯(lián)查詢 root.join("teacher", JoinType.INNER);
fetch() : 抓取連接.
Path
代表一個屬性
使用
查詢所有的學生
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = builder.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
List<Student> lists = em.createQuery(cq).getResultList();
查詢一列
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<String> cq = builder.createQuery(String.class);
Root<Student> root = cq.from(Student.class);
Path<String> name = root.get("name");
cq.select(name);
List<String> lists = em.createQuery(cq).getResultList();
查詢多列
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Object[]> cq = builder.createQuery(Object[].class);
Root<Student> root = cq.from(Student.class);
Path<String> name = root.get("name");
Path<Integer> age = root.get("age");
cq.multiselect(name, age);
List<Object[]> lists = em.createQuery(cq).getResultList();
添加查詢條件
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = builder.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
Path<String> name = root.get("name");
Path<Integer> age = root.get("age");
cq.where(builder.like(name, "%小%"), builder.between(age, 19, 200));
List<Student> lists = em.createQuery(cq).getResultList();
排序
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = builder.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
Path<String> age = root.get("age");
cq.orderBy(builder.desc(age));
List<Student> lists = em.createQuery(cq).getResultList();
統(tǒng)計函數(shù)
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Integer> cq = builder.createQuery(Integer.class);
Root<Student> root = cq.from(Student.class);
Path<Integer> age = root.get("age");
cq.select(builder.sum(age));
Integer res = em.createQuery(cq).getSingleResult();
關聯(lián)查詢
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = builder.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
root.join("teacher", JoinType.INNER);
Path<Integer> t_id = root.get("teacher").get("id");
cq.where(builder.equal(t_id, 1));
List<Student> lists = em.createQuery(cq).getResultList();
抓取連接
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = builder.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
root.fetch("teacher", JoinType.INNER);
List<Student> lists = em.createQuery(cq).getResultList();
hibernate逆向工程
1.準備myeclipse
2.window-->show view-->DB browser
3.在db browser中 new 數(shù)據(jù)庫
Driver timplate 選擇 mysql
Driver name 直接寫一個別名
Connection URL :jdbc:mysql:///test
user name:root
password:root
Driver JARS:驅(qū)動包位置
Driver className:com.mysql.jdbc.Driver
4.創(chuàng)建一個新的webhibernate項目
5.右鍵webhibernate項目-->myeclipse-->project facts[capabilities]-->install hibernate facet
6.設置hibernate版本 hibernate specification version :3.3
7.設置targer runtime :myeclipse generic runtime for javaee 6.0
8.需要配置文件hibernate.cfg.xml
9.java源碼配置java.package:com.shuai.test
10.className:HibernateSessionFactory
11.設置一個DB driver:第三步配置過了
12.添加包
13.選擇要逆向的表
右鍵-->hibernate reverse Engineering
14.選擇java package 選擇路徑
15.create pojo
16.create data object
17.finish即可
OpenSessionInView
在過濾器/攔截器中開啟session,在jsp頁面處理完數(shù)據(jù)之后,再關閉session即可
Interceptor
public class SessionInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Transaction tx = null;
try {
// 1. 創(chuàng)建session
Session session = HibernateUtils.getSession();
// 2. 開啟事務
tx = session.beginTransaction();
// 3. 放行
String result = invocation.invoke(); // // execute處理完,就表示 jsp已經(jīng)處理完畢
return result;
} catch (Exception e) {
tx.rollback();
e.printStackTrace(); // 打印錯誤信息!
return "error";
} finally {
// 4. (執(zhí)行完action.execute方法), 提交事務
tx.commit();
}
}
}
HibernateUtils
public class HibernateUtils {
private static SessionFactory sf;
static {
sf = new Configuration().configure().buildSessionFactory();
}
public static Session getSession() {
return sf.getCurrentSession();
}
}
Controller
public class DeptAction extends ActionSupport{
private int id;
public void setId(int id) {
this.id = id;
}
private Dept dept;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
// 創(chuàng)建service
private DeptService deptService = new DeptService();
@Override
public String execute() throws Exception {
// 主鍵查詢
dept = deptService.findById(id);
return SUCCESS; // execute處理完,就表示 jsp已經(jīng)處理完畢
}
}
jsp使用
<s:iterator value="dept.employees">
<tr>
<td><s:property value="id"/></td>
<td><s:property value="name"/></td>
<td><s:property value="age"/></td>
</tr>
</s:iterator>
session的創(chuàng)建方式
第一種方式-openSession
Session session = sf.openSession();
注意:
1.每次獲取的Session不同
2.可以不使用事務
第二種方式-線程方式創(chuàng)建Session
Session session = sf.getCurrentSession();
注意:
1.一定要配置以線程的方式創(chuàng)建Session
<property name="hibernate.current_session_context_class">thread</property>
2.創(chuàng)建的Session,提交事務,自動關閉session
3.使用getCurrentSession方法必須要有事務環(huán)境
聯(lián)合主鍵
Keys.java - 聯(lián)合主鍵,必須實現(xiàn)可序列化標記
public class Keys implements Serializable{
private String name;
private String address;
}
User.java
public class User {
private Keys key;
private int age;
}
User.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.composite" auto-import="true">
<class name="User" table="t_user_key">
<composite-id name="key">
<key-property name="name"></key-property>
<key-property name="address"></key-property>
</composite-id>
<property name="age"></property>
</class>
</hibernate-mapping>
AppTest.java
@Test
public void save() {
Session session = sf.openSession();
session.beginTransaction();
Keys key = new Keys();
key.setName("Jack");
key.setAddress("gz");
User user = new User();
user.setKey(key);
user.setAge(20);
session.save(user);
session.getTransaction().commit();
session.close();
}
@Test
public void get() {
Session session = sf.openSession();
session.beginTransaction();
Keys key = new Keys();
key.setName("Jack");
key.setAddress("gz");
User user = (User) session.get(User.class, key);
System.out.println(user.getKey().getName());
System.out.println(user.getKey().getAddress());
System.out.println(user.getAge());
session.getTransaction().commit();
session.close();
}
基礎hql查詢
//查詢?nèi)?@Test
public void queryAll() {
Session session = sf.openSession();
session.beginTransaction();
Query q = session.createQuery("from User");
List<User> list = q.list();
session.getTransaction().commit();
session.close();
}
//刪除
@Test
public void delete() {
Session session = sf.openSession();
session.beginTransaction();
Query q = session.createQuery("delete from User where id=1)");
q.executeUpdate();
session.getTransaction().commit();
session.close();
}
//分頁
@Test
public void page() {
Session session = sf.openSession();
session.beginTransaction();
Query q = session.createQuery("from User");
// 設置分頁參數(shù)
q.setFirstResult(0); //相當于 limit 第一個參數(shù) 查詢的其實行
q.setMaxResults(2); //相當于 limit 第二個參數(shù) 查詢返回的行數(shù)
List list = q.list();
session.getTransaction().commit();
session.close();
}
Hql查詢
API
Query
list();//查詢?nèi)?
Query query = session.createQuery("from User");
List<user> list = query.list();//會懶加載
注意:會有一級緩存,緩存數(shù)據(jù).一個id的數(shù)據(jù)只查詢一次
連接查詢
Query query = session.createQuery("from Address a inner join a.user");
List<Object[]> list = query.list();//即時查詢,連接查詢可以解決懶加載問題.
fetch查詢
把右表的數(shù)據(jù)填充到左表
添加fetch查詢語句sql沒有任何變化,變化的是封裝數(shù)據(jù)的方式
Query query = session.createQuery("from Address a inner join a.user");
Query query = session.createQuery("from Address a inner join fetch a.user");