簡介
Hibernate是一個開放源代碼的對象關(guān)系映射框架,它對JDBC進行了非常輕量級的對象封裝,它將POJO與數(shù)據(jù)庫表建立映射關(guān)系,是一個全自動的orm框架,hibernate可以自動生成SQL語句,自動執(zhí)行,使得Java程序員可以隨心所欲的使用對象編程思維來操縱數(shù)據(jù)庫。 Hibernate可以應(yīng)用在任何使用JDBC的場合,既可以在Java的客戶端程序使用,也可以在Servlet/JSP的Web應(yīng)用中使用,最具革命意義的是,Hibernate可以在應(yīng)用EJB的J2EE架構(gòu)中取代CMP,完成數(shù)據(jù)持久化的重任。
特點
面向?qū)ο?br>
不用寫sql語句
簡潔
要寫dao實現(xiàn)
缺點
不能處理批量
hibernate快速入門
1、導(dǎo)包

2、配置文件
<!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>
<!-- 四大參數(shù) -->
<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"></property>
<!-- SQL 方言 ,注意使用MySQLInnoDBDialect,才可以使用Innodb引擎-->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- 打印出sql -->
<property name="show_sql">true</property>
<!-- 格式化sql -->
<property name="format_sql">true</property>
<!-- 有表更新表,沒有表自動創(chuàng)建表 -->
<property name="hbm2ddl.auto">update</property>
<!-- 加載映射文件 -->
<mapping resource="User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
注意:主配置文件名,一般默認是hibernate.cfg.xml,并且在src根目錄中 上面的配置文件,可以參考etc文件夾下的配置文件
創(chuàng)建類
public class User {
private int uid;
private String username;
private String password;
//get/set方法 必須要有
}
3、映射文件
<!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.hibernate.entity.User" table="user">
<id name="uid" column="uid">
<!-- 使用數(shù)據(jù)庫默認的生成主鍵的方案 -->
<generator class="native"/>
</id>
<property name="username" column="username"/>
<property name="password" column="password"/>
</class>
</hibernate-mapping>
4、事務(wù)
Configuration configure = new Configuration().configure("hibernate.cfg.xml");
SessionFactory factory = configure.buildSessionFactory();
Session session = factory.openSession();// 獲取連接
// 開啟事務(wù)
Transaction tx = session.beginTransaction();
User user = new User("黃蓉", "123");
session.save(user);
tx.commit();// 提交事務(wù)
session.close();// 關(guān)閉連接

sessioin查詢api
save、delete、update
get 不支持延遲查詢
load 延遲查詢:如果使用了對象中非id的屬性時才會發(fā)送sql語句
saveOrUpdate
瞬時態(tài)執(zhí)行save(),游離態(tài)執(zhí)行update()
merge
兩個相同id的對象合并
實體類的三種狀態(tài)
瞬時態(tài):
無id,與session無關(guān)聯(lián),與數(shù)據(jù)庫無關(guān)聯(lián)
持久態(tài):
有id,與session有關(guān)聯(lián),與數(shù)據(jù)庫關(guān)聯(lián) 持久態(tài)對象修改數(shù)據(jù),會自動修改數(shù)據(jù)庫的數(shù)據(jù)
游離態(tài)(離線):
有id,與session無關(guān)聯(lián),與數(shù)據(jù)庫有關(guān)

關(guān)聯(lián)關(guān)系
多對一
多個Customer對應(yīng)一個User

一對多
一個User對應(yīng)多個Customer

多對多

hibernate查詢api
oid
就是根據(jù)對象的id查詢,例如get()、load()
hql Query
// -----------------條件查詢-------------------
@Test
public void test1() {
String hql = "from User u where u.uid=1";
Query<User> query = session.createQuery(hql);
User u = query.uniqueResult();
System.out.println(u);
}
@Test
public void test2() {
String hql = "from User u where u.username='lisi' and u.password='123'";
Query<User> query = session.createQuery(hql);
User u = query.uniqueResult();
System.out.println(u);
}
// ---------------占位符條件查詢------------------
// 占位符條件查詢 ?
@Test
public void test3() {
String hql = "from User u where u.username=? and u.password=?";
Query<User> query = session.createQuery(hql);
query.setParameter(0, "lisi");
query.setParameter(1, "123");
User u = query.uniqueResult();
System.out.println(u);
}
// 命名占位符條件查詢1 parameter
@Test
public void test4() {
String hql = "from User where username=:username and password=:password";
Query<User> query = session.createQuery(hql);
query.setParameter("username", "lisi");
query.setParameter("password", "123");
User u = query.uniqueResult();
System.out.println(u);
}
// 命名占位符條件查詢2 javabean
@Test
public void test5() {
String hql = "from User where username=:username and password=:password";
Query<User> query = session.createQuery(hql);
User user = new User("lisi", "123");
query.setProperties(user);
User u = query.uniqueResult();
System.out.println(u);
}
// 命名占位符條件查詢3 map,可以解決命名占位符與實際參數(shù)名不一樣的問題
@Test
public void test6() {
String hql = "from User where username=:user and password=:pwd";
Query<User> query = session.createQuery(hql);
Map<String, String> map = new HashMap<>();
map.put("user", "lisi");
map.put("pwd", "123");
query.setProperties(map);
User u = query.uniqueResult();
System.out.println(u);
}
// 模糊查詢
@Test
public void test7() {
String hql = "from User where username like ?";
Query<User> query = session.createQuery(hql);
query.setParameter(0, "%七%");
List<User> list = query.getResultList();
System.out.println(list);
}
// 查詢列表,并且排序
@Test
public void test8() {
String hql = "from User order by password desc";
Query<User> query = session.createQuery(hql);
List<User> list = query.getResultList();
System.out.println(list);
}
// 分頁查詢
@Test
public void test9() {
String hql = "from User";
Query<User> query = session.createQuery(hql);
query.setFirstResult(0);
query.setMaxResults(3);
List<User> list = query.getResultList();
System.out.println(list);
}
// 動態(tài)查詢
@Test
public void test10() {
User user = new User();
user.setPassword("123");
String hql = "from User where 1=1";
StringBuffer sb = new StringBuffer(hql);
if (user.getPassword() != null && user.getPassword() != "") {
sb.append(" and password=:password");
}
Query<User> query = session.createQuery(sb.toString());
query.setProperties(user);
List<User> list = query.getResultList();
System.out.println(list);
}
// --------------------連接------------------------
// 內(nèi)連接,封裝成數(shù)組,對象數(shù)組 查詢roleid=1的用戶
@Test
public void test11() {
String hql = "from User u inner join u.roleSet ro where ro.roleid=1";
Query<Object[]> query = session.createQuery(hql);
List<Object[]> list = query.getResultList();
for (Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}
}
// 迫切內(nèi)連接,直接封裝成對象 查詢custid=1的用戶
@Test
public void test12() {
String hql = "from User u inner join fetch u.custSet c where c.custid=1";
Query<User> query = session.createQuery(hql);
List<User> list = query.getResultList();
System.out.println(list.size());
System.out.println(list.get(0) + ":" + list.get(0).getCustSet());
}
@Test
public void test13() {
String hql = "from User u where u.username='洪七公'";
Query<User> query = session.createQuery(hql);
List<User> list = query.list();
System.out.println(list.size());
System.out.println(list.get(0).getCustSet());
}
// -----------------投影查詢--------------------
// 投影查詢 object[]
@Test
public void test14() {
String hql = "select username,password from User u where u.uid=1";
Query<Object[]> query = session.createQuery(hql);
Object[] obj = query.uniqueResult();
System.out.println(Arrays.toString(obj));
}
// 查詢一個值的時候,只能使用Object,不能用數(shù)組
@Test
public void test15() {
String hql = "select count(*) from User";
Query<Object> query = session.createQuery(hql);
Object obj = query.uniqueResult();
System.out.println(obj);
}
// 投影查詢 list集合
@Test
public void test16() {
String hql = "select new list(username,password) from User u where u.uid=1";
Query<List<String>> query = session.createQuery(hql);
List<String> list = query.uniqueResult();
System.out.println(list);
}
// 投影查詢 map集合
@Test
public void test17() {
String hql = "select new map(username,password) from User u where u.uid=1";
Query<Map<String, String>> query = session.createQuery(hql);
Map<String, String> map = query.uniqueResult();
System.out.println(map);
}
// 投影查詢 自定義對象
// 注意:new User(uid,username,password)會調(diào)用對應(yīng)的構(gòu)造方法,沒有就會報錯
@Test
public void test18() {
String hql = "select new User(username,password) from User u where u.uid=1";
Query<User> query = session.createQuery(hql);
User user = query.uniqueResult();
System.out.println(user);
}
qbc Citira
// 模糊查詢
@Test
public void test2() {
Criteria criteria = session.createCriteria(User.class)
.add(Restrictions.like("username", "%七%"));
List<User> list = criteria.list();
System.out.println(list);
}
// 多條件查詢
@Test
public void test3() {
Criteria criteria = session.createCriteria(User.class)
.add(Restrictions.eq("username", "李四"))
.add(Restrictions.eq("password", "123"));
List<User> list = criteria.list();
System.out.println(list);
}
//排序
@Test
public void test4() {
Criteria criteria = session.createCriteria(User.class)
.addOrder(Order.desc("password"));//降序
List<User> list = criteria.list();
System.out.println(list);
}
//分頁
@Test
public void test5() {
Criteria criteria = session.createCriteria(User.class)
.setFirstResult(3)
.setMaxResults(3);
List<User> list = criteria.list();
System.out.println(list);
}
//---------------------投影查詢---------------------
//聚合函數(shù) count()
@Test
public void test6(){
Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(Projections.rowCount());//count()
Object result = criteria.uniqueResult();
System.out.println(result);
}
//分組計算
@Test
public void test7(){
Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(Projections.projectionList()
.add(Projections.rowCount())
.add(Projections.groupProperty("password")));
List<Object[]> list = criteria.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
}
//選出部分字段
@Test
public void test8(){
Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(Projections.projectionList()
.add(Projections.property("username"))
.add(Projections.property("password")));
List<Object[]> list = criteria.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
}
hibernate緩存
一級緩存
第一次查找,去緩存中找,沒有數(shù)據(jù),從數(shù)據(jù)庫獲取,然后存入一級緩存,并且存入快照區(qū);session沒有關(guān)閉,并且執(zhí)行第二次查找,先從一級緩存中獲取。如果對象修改了數(shù)據(jù),一級緩存中的數(shù)據(jù)也修改了,那么會將一級緩存和快照區(qū)的數(shù)據(jù)進行比對,如果不相同,就將數(shù)據(jù)存入數(shù)據(jù)庫。
第一級別的緩存是 Session 級別的緩存,它是屬于事務(wù)范圍的緩存(session的一級緩存)
二級緩存
二級緩存屬于SessionFactory級別的緩存,緩存的對象根據(jù)提供的實現(xiàn)類不同,放置的位置也不同,主要就是內(nèi)存和硬盤中。二級緩存是緩存對象的Id,所以只有通過id查詢的,二級緩存才能生效。
第二級別的緩存是 SessionFactory 級別的緩存,它是屬于進程范圍的緩存
二級緩存的實現(xiàn)有很多,我們使用ehcache來實現(xiàn)二級緩存
1、導(dǎo)包
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.0.12.Final</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.11</version>
</dependency>
2、在spring-hibernate.xml中配置
<!-- 開啟二級緩存:根據(jù)id來查詢 -->
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<!-- 開啟查詢緩存:根據(jù)非id來查詢,需要在query中設(shè)置setCacheable(true) -->
<prop key="hibernate.cache.use_query_cache">true</prop>
<!-- 高速緩存提供程序 -->
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
3、在resources根目錄中添加ehcache.xml文件
<ehcache>
<!--
指定二級緩存存放在磁盤上的位置,可以使用磁盤目錄
也可以使用Java System Property目錄
user.home是用戶目錄
user.dir是用戶當(dāng)前工作目錄
java.io.tmpdir是默認臨時文件路徑
-->
<diskStore path="java.io.tmpdir/cache"/>
<!-- ehcache將緩存分為多個不同的區(qū)域,不同的區(qū)域可以設(shè)置不同的緩存策略 -->
<!--緩存策略:
name:Cache的唯一標識。
maxElementsInMemory:內(nèi)存中最大緩存對象數(shù)。
eternal:Element是否永久有效,一旦設(shè)置true,timeout將不起作用。
timeToIdleSeconds:設(shè)置Element在失效前的允許閑置時間。僅當(dāng)element不是永久有效時使用,可選屬性,默認值是0,也就是可閑置時間無窮大。
timeToLiveSeconds:設(shè)置Element在失效前允許存活時間。最大時間介于創(chuàng)建時間和失效時間之間。僅當(dāng)element不是永久有效時使用,默認是0.,也就是element存活時間無窮大。
overflowToDisk:配置此屬性,當(dāng)內(nèi)存中Element數(shù)量達到maxElementsInMemory時,Ehcache將會Element寫到磁盤中。
maxElementsOnDisk:磁盤中最大緩存對象數(shù),若是0表示無窮大。
memoryStoreEvictionPolicy:當(dāng)達到maxElementsInMemory限制時,Ehcache將會根據(jù)指定的策略
去清理緩存中的內(nèi)容。默認策略是LRU(最近最少使用),你也可以設(shè)置為FIFO(先進先出)或是LFU(較少使用) -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="simple"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
<!--可以給每個實體類指定一個配置文件,通過name屬性指定,要使用類的全名-->
<!--<cache name="com.study.entity.User"-->
<!--maxElementsInMemory="10000"-->
<!--eternal="false"-->
<!--timeToIdleSeconds="300"-->
<!--timeToLiveSeconds="600"-->
<!--overflowToDisk="true"-->
<!--/>-->
</ehcache>
4、在需要使用二級緩存的類上添加注解
//region:標示要使用的區(qū)域,不同的區(qū)域使用的緩存策略不一樣,見上面第3點說明
//usage:指定使用的并非策略
@org.hibernate.annotations.Cache(region ="simple",usage = CacheConcurrencyStrategy.READ_ONLY)
ehcache的四種緩存并發(fā)策略如下:
read-write(讀寫型):
提供Read Committed事務(wù)隔離級別
在非集群的環(huán)境中適用
適用經(jīng)常被讀,很少修改的數(shù)據(jù)
可以防止臟讀
更新緩存的時候會鎖定緩存中的數(shù)據(jù)
nonstrict-read-write(非嚴格讀寫型):
適用極少被修改,偶爾允許臟讀的數(shù)據(jù)(兩個事務(wù)同時修改數(shù)據(jù)的情況很少見)
不保證緩存和數(shù)據(jù)庫中數(shù)據(jù)的一致性
為緩存數(shù)據(jù)設(shè)置很短的過期時間,從而盡量避免臟讀
不鎖定緩存中的數(shù)據(jù)
read-only(只讀型):
適用從來不會被修改的數(shù)據(jù)(如參考數(shù)據(jù))
在此模式下,如果對數(shù)據(jù)進行更新操作,會有異常
事務(wù)隔離級別低,并發(fā)性能高
在集群環(huán)境中也能完美運作
5、測試
AppInfo appInfo = appInfoService.findOneById(1);
System.out.println(appInfo);
AppInfo appInfo1 = appInfoService.findOneById(1);
System.out.println(appInfo1);
注意:
1、list()只查詢一級緩存,而iterator()會從二級緩存中查
2、list()方法返回的對象都是實體對象,而iterator()返回的是代理對象
查詢緩存
Query Cache只是在特定的條件下才會發(fā)揮作用,而且要求相當(dāng)嚴格:
完全相同的HQL重復(fù)執(zhí)行。(注意,只有hql)
重復(fù)執(zhí)行期間,Query Cache對應(yīng)的數(shù)據(jù)表不能有數(shù)據(jù)變動(比如添、刪、改操作)
絕大多數(shù)的查詢并不能從查詢緩存中受益,所以Hibernate默認是不進行查詢緩存的。查詢緩存適用于以下場合:
在應(yīng)用程序運行時經(jīng)常使用的查詢語句(參數(shù)相同)
很少對與查詢語句檢索到的數(shù)據(jù)進行插入、刪除或更新操作
Query query = session.createQuery(hql);
query.setCacheable(true); //啟用查詢緩存
query.setCacheRegion(“queryCacheRegion”); //設(shè)置查詢緩存區(qū)域(數(shù)據(jù)過期策略)
query.list();