1. 程式人生 > >2018年3月25日學習筆記

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();}}

表單驗證

註解