2018年3月25日學習筆記
實現Product和Category多對一的關係
1.在Product類中增加Category屬性
2.在Product.hbm.xml中設定Category多對一的關係
<many-to-one name="category" class="Category" column="cid" />
name="category"對應Product類中的category屬性
class="Category"表示對應Category類
column="cid"表示指向category_表的外來鍵,即cid是category_表的外來鍵
3.在hibernate.cfg.xml中增加Category的對映(與Product相似)
增加了一個新的Category物件c1,並將其設定成id=8的product的category
Category c =
new
Category();
c.setName(
"c1"
);
s.save(c);
Product p = (Product) s.get(Product.
class
,
8
);
p.setCategory(c);
s.update(p)
實現Category和Product一對多的關係
1.在Product中增加一個Set的集合
2.在Category.hbm.xml中增加one-to-many的對映
<set name="products" lazy="false"> <key column="cid" not-null="false" /> <one-to-many class="Product" /></set>lazy=“false”表示不使用延遲載入
not-null=false表示Product相對於Category的外來鍵是cid且可以為空
實現Product和User之間多對多的關係
1.User中維護一個Product的集合
2.在相應的.hbm.xml中增加了many-to-many的對映
<
set
name
=
"products"
table
=
"user_product"
lazy
=
"false"
>
<
key
column
=
"uid"
/>
<
many-to-many
column
=
"pid"
class
=
"Product"
/>
</
set
>
突然發現並不一定要用SQL語句手動建立表而只需要在檔案中進行配置就可以了……
果然在教程的評論裡發現有人和我有一樣的疑問……
解釋是:在hibernate.cfg.xml配置檔案裡有一個 <property name="hbm2ddl.auto">update</property>, 會導致表結構自動建立和修改,以前只以為update是自動更新相關資料的意思,沒想到還有自動建立表的功能
還有額外的收穫是有人注意到了雖然User和Product保持著多對多的關係,但是product的user屬性卻是null,這體現出了兩者之間的關係只能通過中間表來體現,這就是和一對多,多對一關係的不同之處了
Hibernate任何對資料有改動的操作,都應該放在事務裡面,如前文提到的那樣,這要求MySQL是支援InnoDB的
Hibernate的延遲載入
屬性延遲載入:當使用load方法來獲取物件的時候,只有當訪問了這個物件的屬性,Hibernate才會到資料庫中查詢,否則並不會訪問資料庫。
關係的延遲載入:當要獲取category_表的資訊的時候,並不會查詢product_表,只有通過category獲取product的時候,才會進行對於product_表的查詢。
級聯操作:在沒有配置級聯的時候,刪除分類,其分類下對應的產品並不會被刪除
級聯有四種類型:1.all:所有操作都執行級聯操作;2.none:所有操作都不支援級聯操作
3.delete:刪除時執行級聯操作;在Category中:
<set name="products" cascade="delete" lazy="false">
4.save-update:儲存和更新時執行級聯操作
級聯操作通常用於one-many和many-to-many上,幾乎不會用在many-one上
<set name="products" cascade="save-update" lazy="false">
會把沒有新增到資料庫裡的瞬時狀態的產品物件持久化
Hibernate的一級快取是在Session上,二級快取是在SessionFactory上
Hibernate使用Criteria進行分頁查詢
Criteria c= s.createCriteria(Product.
class
);
c.add(Restrictions.like(
"name"
,
"%"
+name+
"%"
));
c.setFirstResult(
2
);
c.setMaxResults(
5
);
表示從第二條資料開始,一共查詢五條資料
get和load兩種獲取方式:對於id不存在的情況,get方法會返回null,load方法會丟擲異常
1. 獲取的是否是同一個session物件
openSession每次都會得到一個新的Session物件
getCurrentSession在同一個執行緒中,每次都是獲取相同的Session物件,但是在不同的執行緒中獲取的是不同的Session物件
2. 事務提交的必要性
openSession只有在增加,刪除,修改的時候需要事務,查詢時不需要的
getCurrentSession是所有操作都必須放在事務中進行,並且提交事務後,session就自動關閉,不能夠再進行關閉
Hibernate有快取機制,可以通過用id作為key把product物件儲存在快取中
同時hibernate也提供Query的查詢方式。假設資料庫中有100條記錄,其中有30條記錄在快取中,但是使用Query的list方法,就會所有的100條資料都從資料庫中查詢,而無視這30條快取中的記錄
N+1是什麼意思呢,首先執行一條sql語句,去查詢這100條記錄,但是,只返回這100條記錄的ID
然後再根據id,進行進一步查詢。
如果id在快取中,就從快取中獲取product物件了,否則再從資料庫中獲取
s.beginTransaction();
String name =
"iphone"
;
Query q =s.createQuery(
"from Product p where p.name like ?"
);
q.setString(
0
,
"%"
+name+
"%"
);
Iterator<Product> it= q.iterate();
while
(it.hasNext()){
Product p =it.next();
System.out.println(p.getName());
}
s.getTransaction().commit();
突然聯想到基於1的和基於0的,返回查詢發現是PreparedStatement模糊查詢是基於1的
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES SET SALARY = ? WHERE ID = ?"); pstmt.setBigDecimal(1, 153833.00)返回查詢總數:
s.beginTransaction();
String name =
"iphone"
;
Query q =s.createQuery(
"select count(*) from Product p where p.name like ?"
);
q.setString(
0
,
"%"
+name+
"%"
);
long
total= (Long) q.uniqueResult();
System.out.println(total);
s.getTransaction().commit();
樂觀鎖:<version name="version" column="ver" type="int"></version>增加一個version欄位,用於版本資訊控制。這就是樂觀鎖的核心機制。
比如session1獲取product1的時候,version=1。 那麼session1更新product1的時候,就需要確保version還是1才可以進行更新,並且更新結束後,把version改為2。
注意: version元素必須緊跟著id後面,否則會出錯。
1. 假設資料庫中產品的價格是10000,version是10
2. session1,session2分別獲取了該物件
3. 都修改了物件的價格
4. session1試圖儲存到資料庫,檢測version依舊=10,成功儲存,並把version修改為11
5. session2試圖儲存到資料庫,檢測version=11,說明該資料已經被其他人動過了。 儲存失敗,丟擲異常
C3P0連線池
Hibernate的註解:本來放在.hbm.xml中的檔案對映資訊,不用配置檔案而改用註解來完成
MVC
僅僅使用Servlet的短處:不僅要準備資料,還要準備HTML,可讀性很差,寫起來也很麻煩
僅僅使用JSP的短處:寫Java程式碼不如在Servlet中方便
結合Servlet和JSP
public
class
HeroEditServlet
extends
HttpServlet {
protected
void
service(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
int
id = Integer.parseInt(request.getParameter(
"id"
));
Hero hero =
new
HeroDAO().get(id);
request.setAttribute(
"hero"
, hero);
request.getRequestDispatcher(
"editHero.jsp"
).forward(request, response);
}
}
實現獲取資料然後跳轉到jsp頁面
<%@ page language=
"java"
contentType=
"text/html; charset=UTF-8"
pageEncoding=
"UTF-8"
import
=
"java.util.*,bean.*,java.sql.*"
%>
<form action=
'updateHero'
method=
'post'
>
名字 : <input type=
'text'
name=
'name'
value=
'${hero.name}'
> <br>
血量 :<input type=
'text'
name=
'hp'
value=
'${hero.hp}'
> <br>
傷害: <input type=
'text'
name=
'damage'
value=
'${hero.damage}'
> <br>
<input type=
'hidden'
name=
'id'
value=
'${hero.id}'
>
<input type=
'submit'
value=
'更新'
>
</form>
不做查詢資料庫的事情,直接獲取從HeroEditServlet傳過來的Hero物件
MVC Model View Controller
控制器的作用就是把不同的資料,顯示在不同的檢視上
DAO:
public HeroDAO() { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); }}把驅動的初始化的方法放在HeroDAO中
提供一個getConnection()的方法返回連線:所有的資料庫操作都需要事先拿到一個數據庫連線Connection
驗證使用者是否登入
從session中取出userName,如果是空,就表示使用者沒有登入,或者登入已經超過了30分鐘。 客戶端跳轉到login.html,讓使用者重新登陸
struts
1.所有的訪問都會被web.xml中配置的Struts的Filter所攔截
2.攔截之後,就進入Struts的工作流程
3.訪問的地址是/index,根據Struts按照struts.xml的配置,伺服器跳轉到index.jsp
4.顯示index.jsp的內容
在struts中也可以獲取Servlet包中的request和response物件
struts中的Session有兩個
一個是傳統的servlet包下的HttpSession
另一個是Struts中自己定義的Session
傳統的servlet包下的session的獲取辦法是:
ServletActionContext.getRequest().getSession();
使用該方法,需要在eclipse的專案中匯入servlet-api.jar,可以在右邊下載
新的Session的獲取辦法是
Map m = ActionContext.getContext().getSession();
這個session以Map類的形式出現,其中的值和HttpSession中的值是同步的
struts的專屬標籤庫
form標籤用於提交資料
<
s:form
action
=
"addProduct"
>
<
s:textfield
name
=
"product.name"
label
=
"product name"
/>
<
s:submit
value
=
"Submit"
/>
</
s:form
>
提供s:iterator用於遍歷一個集合中的資料
1.為ProductAction增加list()方法
為ProductAction增加一個products屬性,型別是List,並提供get()和set()方法
為ProductAction增加一個list()方法,為products新增3個product物件,並返回list
2.在struts.xml中配置路徑listProduct,並返回list.jsp
萬用字元匹配
攔截器:
package
com.how2java.interceptor;
import
java.util.Date;
import
com.how2java.action.ProductAction;
import
com.opensymphony.xwork2.ActionInvocation;
import
com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public
class
DateInterceptor
extends
AbstractInterceptor {
public
String intercept(ActionInvocation invocation)
throws
Exception {
ProductAction action = (ProductAction)invocation.getAction();
action.setDate(
new
Date());
return
invocation.invoke();
}
}
表單驗證
註解