※依PK的CRUD
SQL腳本CREATE TABLE DEPT ( DEPTNO NUMBER(10,0) NOT NULL, DNAME VARCHAR2(255 BYTE), LOC VARCHAR2(255 BYTE), PRIMARY KEY ("DEPTNO") ); Insert into DEPT (DEPTNO,DNAME,LOC) values (70,'DDD','zzz'); Insert into DEPT (DEPTNO,DNAME,LOC) values (100,'eee','jjj'); Insert into DEPT (DEPTNO,DNAME,LOC) values (10,'ACCOUNTING','NEW YORK'); Insert into DEPT (DEPTNO,DNAME,LOC) values (20,'RESEARCH','DALLAS'); Insert into DEPT (DEPTNO,DNAME,LOC) values (30,'SALES','CHICAGO'); Insert into DEPT (DEPTNO,DNAME,LOC) values (40,'OPERATIONS','BOSTON'); Insert into DEPT (DEPTNO,DNAME,LOC) values (90,'bruce','ZH_TW'); Insert into DEPT (DEPTNO,DNAME,LOC) values (80,'bruce','ZH_TW');
pom.xml
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.6.10.Final</version> </dependency> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.19.0-GA</version> </dependency>
javassist不加的話,會在執行時,出「java.lang.ClassNotFoundException: javassist.util.proxy.MethodFilter」
hibernate.cfg.xml
<hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@127.0.0.1:1521:orcl</property> <property name="hibernate.connection.username">account</property> <property name="hibernate.connection.password">password</property> <property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <mapping resource="org/hibernate/vo/Dept.hbm.xml" /> </session-factory> </hibernate-configuration>
Dept.hbm.xml
<hibernate-mapping> <class name="org.hibernate.vo.Dept" table="DEPT"> <id name="deptno" type="int"> <column name="DEPTNO" /> <generator class="assigned" /> </id> <property name="dname" type="java.lang.String" access="field"> <column name="DNAME" /> </property> <property name="loc" type="java.lang.String" column name="LOC" /> </class> </hibernate-mapping>※hibernate-mapping有個屬性package,打上package名稱,而class name打class名稱也是可以
※property也可只寫一行,最後一行的property就是這樣
Dept.java
private int deptno; private String dname; private String loc; //setter/getter
TestHibernate.java
Configuration cfg = new Configuration().configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); Dept dept = new Dept(); dept.setDeptno(80); dept.setDname("bruce"); dept.setLoc("ZH_TW"); Transaction tx = session.beginTransaction(); try { session.save(dept); tx.commit(); System.out.println("成功!"); } catch (Exception e) { tx.rollback(); System.err.println("失敗!"); e.printStackTrace(); } finally { session.close(); factory.close(); }
專案圖:
TestHibernate.java的session.save(dept);是新增的意思,重要的有六個
※delete:刪除
※save:新增
※update:修改
※saveOrUpdate:新增或修改(資料庫沒有-->新增,有-->修改)
較專業的講法是:如果物件是Transient,就呼叫save(); 如果物件是Detached,則呼叫update()
可參考官方網站和良葛格的
只是官網只有三種狀態,良葛格的有四種,而且還有圖,不知從哪來的?
※load:查詢
※get:查詢
※get與load的差別
Configuration cfg = new Configuration().configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); System.out.println("0"); //Dept dept = (Dept) session.get(Dept.class, 80); Dept dept = (Dept) session.load(Dept.class, 80); System.out.println(dept);
因為load()為lazy-initialization,只有真正要用到時,才會真的去做事,
所以load()效能比get()還要高
※如果沒查到:
get()是null
load()會拋org.hibernate.ObjectNotFoundException: No row with the given identifier exists:
※注意事項
Dept dept = (Dept) session.get(Dept.class, 80); dept.setDname("apple"); Transaction tx = session.beginTransaction(); try { //session.save(dept);此行不加也行 tx.commit(); System.out.println("成功!"); } catch (Exception e) { tx.rollback(); System.err.println("失敗!"); e.printStackTrace(); } finally { session.close(); factory.close(); }
先get或load,然後再set也能成功修改,但還是要commit
如上面的程式碼,整個都在Transaction外面,還是可以
※session混合
Configuration cfg = new Configuration().configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); Dept dept = (Dept) session.load(Dept.class, 80); dept.setDname("xxx3"); session.close(); Session session2 = factory.openSession(); dept.setLoc("ZH_TW");// 此行對DB無效,因為session已關閉,dept是包在裡面的 // session2.update(dept);// 這行才有用 Transaction tx = session2.beginTransaction(); try { tx.commit(); System.out.println("成功!"); } catch (Exception e) { tx.rollback(); System.err.println("失敗!"); e.printStackTrace(); } finally { session2.close(); factory.close(); }
注意下面的Transaction接收的是session2
session關閉對資料庫沒作用,但java也不會出錯
※資料庫的抓取欄位策略
<hibernate-mapping default-access="field"> <class name="org.hibernate.vo.Dept" table="DEPT"> <id name="deptNo" type="int" access="property"> <column name="DEPTNO" /> <generator class="assigned" /> </id> <property name="dName" type="java.lang.String" access="property"> <column name="DNAME" /> </property> <property name="loc" type="java.lang.String" access="property"> <column name="LOC" /> </property> </class> </hibernate-mapping>
id和property有個屬性access,有三個可以設定
※property:預設值,vo一定要設setter/getter,不然會報「Could not find a setter for property xxx in class xxx」
※field:hibernate會用反射的技術獲取值
※noop:自定的策略,要implements org.hibernate.property.PropertyAccessor介面
可參考這裡的5.1.4.2
※hibernate-mapping也有default-access可以設定,上面是針對一個field,這邊的設定是針對整個java bean,但如果都設定,以上面的為主
※我設定field後,將setter/getter刪除,欄位還是private
使用get可以抓到值; 使用load,值都是null
※事務自動提交
在hibernate.cfg.xml加上<property name="hibernate.connection.autocommit">true</property>
TestHibernate.java
Configuration cfg = new Configuration().configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); Dept dept = new Dept(); dept.setDeptno(80); dept.setDname("bruce"); dept.setLoc("zh_TW"); session.saveOrUpdate(dept); session.flush(); // Transaction tx = session.beginTransaction(); try { session.saveOrUpdate(dept); // tx.commit(); System.out.println("成功!"); } catch (Exception e) { // tx.rollback(); System.err.println("失敗!"); e.printStackTrace(); } finally { session.close(); factory.close(); }
主要就是加上session.flush();
※多個執行一起commit
再創一個腳本CREATE TABLE EMP ( EMPNO NUMBER(4,0), ENAME VARCHAR2(10 BYTE), JOB VARCHAR2(9 BYTE), MGR NUMBER(4,0), HIREDATE DATE, SAL NUMBER(7,2), COMM NUMBER(7,2), DEPTNO NUMBER(2,0), CONSTRAINT "PK_EMP" PRIMARY KEY (EMPNO) ); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (9999,'Bruce','MANAGER',null,to_date('18-10月-15','DD-MON-RR'),5000,null,80); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7369,'SMITH','CLERK',7902,to_date('17-12月-80','DD-MON-RR'),800,null,20); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7499,'ALLEN','SALESMAN',7698,to_date('20-2月 -81','DD-MON-RR'),1600,300,30); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7521,'WARD','SALESMAN',7698,to_date('22-2月 -81','DD-MON-RR'),1250,500,30); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7566,'JONES','MANAGER',7839,to_date('02-4月 -81','DD-MON-RR'),2975,null,20); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7654,'MARTIN','SALESMAN',7698,to_date('28-9月 -81','DD-MON-RR'),1250,1400,30); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7698,'BLAKE','MANAGER',7839,to_date('01-5月 -81','DD-MON-RR'),2850,null,30); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7782,'CLARK','MANAGER',7839,to_date('09-6月 -81','DD-MON-RR'),2450,null,10); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7788,'SCOTT','ANALYST',7566,to_date('24-1月 -87','DD-MON-RR'),3000,null,20); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7839,'KING','PRESIDENT',null,to_date('17-11月-81','DD-MON-RR'),5000,null,10); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7844,'TURNER','SALESMAN',7698,to_date('08-9月 -81','DD-MON-RR'),1500,0,30); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7876,'ADAMS','CLERK',7788,to_date('02-4月 -87','DD-MON-RR'),1100,null,20); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7900,'JAMES','CLERK',7698,to_date('03-12月-81','DD-MON-RR'),950,null,30); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7902,'FORD','ANALYST',7566,to_date('03-12月-81','DD-MON-RR'),3000,null,20); Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7934,'MILLER','CLERK',7782,to_date('23-1月 -82','DD-MON-RR'),1300,null,10);
Emp.java
private int empno; private String ename; private String job; private Integer mgr; private Date hiredate; private Double sal; private Double comm; private Integer deptno; //setter/getter
Emp.hbm.xml
<class name="org.hibernate.vo.Emp" table="Emp"> <id name="empno" type="int"> <column name="EMPNO" /> <generator class="assigned" /> </id> <property name="ename" type="java.lang.String"> <column name="ENAME" /> </property> <property name="job" type="java.lang.String"> <column name="JOB" /> </property> <property name="mgr" type="java.lang.Integer"> <column name="MGR" /> </property> <property name="hiredate" type="java.util.Date"> <column name="HIREDATE" /> </property> <property name="sal" type="java.lang.Double"> <column name="SAL" /> </property> <property name="comm" type="java.lang.Double"> <column name="COMM" /> </property> <property name="deptno" type="java.lang.Integer"> <column name="DEPTNO" /> </property> </class>
hibernate.cfg.xml要多增加一行
<mapping resource="org/hibernate/vo/Emp.hbm.xml" />
TestHibernate.java
public static void main(String[] args) { Configuration cfg = new Configuration().configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); try { session.saveOrUpdate(saveOrUpdateDept()); session.save(saveEmp()); session.flush(); System.out.println("成功!"); } catch (Exception e) { System.err.println("失敗!"); e.printStackTrace(); } finally { session.close(); factory.close(); } } public static Dept saveOrUpdateDept(){ Dept dept = new Dept(); dept.setDeptno(80); dept.setDname("bruce"); dept.setLoc("zh_TW"); return dept; } public static Emp saveEmp(){ Emp emp = new Emp(); emp.setEmpno(9999); emp.setEname("Bruce"); emp.setJob("MANAGER"); emp.setHiredate(new Date()); emp.setSal(5000D); emp.setDeptno(80); return emp; }
※如果是PK可以設定int,不是的話就設Integer,因為int不可以是null,如果怕錯就全部設Wrapper類別
※先用get方法測試Emp行不行,如果如上行設成int,查詢時若資料庫對應的欄位有null值,會出「Null value was assigned to a property of primitive type setter of xxx」的錯
※save是新增,所以執行第二次之後,一定會報錯
※讀取到session.flush();因為是同一個session,會一起commit
※如果要一個一個commit,就在下方多增加一行session.flush(),如下:
session.saveOrUpdate(saveOrUpdateDept()); session.flush(); session.save(saveEmp()); session.flush();
※動態模型
就是沒有class和資料庫的表對應,直接取一個entity名稱就搞定了Dept.hbm.xml
<class entity-name="entityDept" table="DEPT"> <id name="deptno" type="int"> <column name="DEPTNO" /> <generator class="sequence"> <param name="sequence">DEPT_SEQ</param> </generator> </id> <property name="dname" type="java.lang.String" access="field"> <column name="DNAME" /> </property> <property name="loc" type="java.lang.String" column="LOC" /> </class>
※這裡的PK用自動的,如果資料庫沒有就下CREATE SEQUENCE DEPT_SEQ吧!
※property的name為必填
新增測試
Session s = HibernateUtil2.getSession(); Transaction tx = s.beginTransaction(); try { Map<String, Object> dept = new HashMap<>(); dept.put("dname", "業務部"); dept.put("loc", "芝加哥"); s.save("entityDept", dept); tx.commit(); } catch (Exception e) { tx.rollback(); System.err.println("例外錯誤!"); e.printStackTrace(); } finally { if (s.isOpen()) { s.close(); } } }
※map的key是xml的property裡面的name屬性
修改測試
// Map<String, Object> dept = new HashMap<>(); // dept.put("deptno", 41); // dept.put("dname", "業務部"); // dept.put("loc", "舊金山"); // s.update("entityDept", dept); Map<String, Object> dept = (Map<String, Object>) s.get("entityDept", 41); dept.put("loc", "舊金山"); s.update("entityDept", dept); tx.commit();
※註解的部分也可以,但不寫出來就會給null,這張表只有三個欄位,全寫出來也還好,但如果有很多欄位,譬如20個,那實在是太累了,所以可以用get或load取出來,然後再針對想修改的欄位做修改即可
刪除測試
s.delete(s.load("entityDept", 41)); tx.commit();
沒有留言:
張貼留言