<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                和上節的思想一樣。我們如下開發: 1. 定制路由 2. 開發C 3. 開發V 4. 測試C與V是否成功對接 5. 開發M 6. 測試M 7. 對接C與M 8. 對接V與C 9. 集成測試 在現階段,可以說所有的開發步驟都離不開上述的9步。 # 定制路由 ``` <!-- 更新數據 --> <action name="update" class="teacher.Update"> <result name="success">/jsp/success.jsp</result> <result name="error">/jsp/error.jsp</result> </action> ``` # C ``` package teacher; import entity.Teacher; public class Update { private int id; private String name; private String username; private Boolean sex; private String password; private String email; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Boolean getSex() { return sex; } public void setSex(String sex) { if (sex.equals("0")) { this.sex = false; } else { this.sex = true; } } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } // 該execute方法將被自動調用, 方法的返回類型必須為String public String execute() { // 獲取要編輯的教師,并實例化 Teacher teacher = new Teacher(id, name, username, email, sex, password); // 打印查看獲取到的信息 System.out.println(teacher.toString()); return "success"; } } ``` # V V層文件,我們仍然使用統一的success.jsp. 已存在。無需更改. # 測試C與V是否成功對接 ![測試](https://box.kancloud.cn/1ad2f21377bd630b321d4145d9029318_549x222.gif) # M ``` public Boolean update() { // 創建會話(這里的session也是會話的意思,我們以前接觸的http中的session,處理的是用戶與服務器的對話) Session session = MysqlJavaee.getCurrentSession(); // 開啟事務(使用緩沖池進行數據庫的連接) Transaction transaction = session.beginTransaction(); // 在這里,必須使用try catch finally語句。來確定會話正常關閉. // 否則,當操作數據庫產生錯誤時,你可能需要重啟mysql服務 try { // 獲取對象 // 使用Teacher.class來獲取到Teacher的類名(包括包名) Teacher teacher = (Teacher) session.get(Teacher.class, id); // 賦值 teacher.setName(name); teacher.setEmail(email); teacher.setPassword(password); teacher.setSex(sex); // 更新 session.update(teacher); // 提交事務 transaction.commit(); // 捕獲異常 } catch (HibernateException e) { // 如果事務執行異常,則回滾事務 if (null != transaction) { transaction.rollback(); } // 打印異常 e.printStackTrace(); } finally { // 如果session處于開啟狀態,則關閉session if (session.isOpen()) { // 關閉會話 session.close(); } } return true; } ``` ## 測試 ``` @Test public void update() { Teacher teacher = Teacher.getTeacherById(1); System.out.println("更新操作前"); System.out.println(teacher.toString()); // 更新 teacher = new Teacher(1, "this is lisi", "zhangsan", "zhangsan@yunzhiclub.com", false, "123"); teacher.update(); // 查看結果 teacher = Teacher.getTeacherById(1); System.out.println("更新操作后"); System.out.println(teacher.toString()); } ``` 我們可以對`(1, "this is zhangsan", "zhangsan", "zhangsan@yunzhiclub.com", false, "123")`的值進行更改,然后執行測試并查看控制臺,同時查看數據表中的數據是否做了更新(初期的時候很重要). # C對接M ``` // 該execute方法將被自動調用, 方法的返回類型必須為String public String execute() { // 獲取要編輯的教師,并實例化 Teacher teacher = new Teacher(id, name, username, email, sex, password); // 更新 teacher.update(); return "success"; } ``` # V對接C ``` // 該execute方法將被自動調用, 方法的返回類型必須為String public String execute() { // 獲取要編輯的教師,并實例化 Teacher teacher = new Teacher(id, name, username, email, sex, password); // 更新 teacher.update(); return "success"; } ``` # 集成測試 [http://localhost:8080/javaee/teacher/edit?id=1](http://localhost:8080/javaee/teacher/edit?id=1), 添加數據后點擊submit,查看數據表是否進行更新操作. # 重構代碼 如果你前面學習夠扎實的話,相信肯定能夠方法,我們在update()方法中獲取要更新的對象時,是完全可以使用`getTeacherById`來替換`Teacher teacher = (Teacher) session.get(Teacher.class, id);`的。從軟件工程的角度上來講,我們也應該這樣做。原因就不用說了吧:不造相同的輪子. 現在,讓我們修改并測試一下。 ## 代碼修改 ``` // 獲取對象 // 使用Teacher.class來獲取到Teacher的類名(包括包名) Teacher teacher = this.getTeacherById(id); // 賦值 teacher.setName(name); ``` ## 單元測試 進行單元測試,我們得到了一個異常: ``` 更新操作前 Teacher [id=1, name=hello, username=zhangsan, email=zhangsan@yunzhiclub.com, sex=false, password=] org.hibernate.TransactionException: nested transactions not supported Hibernate: select teacher0_.id as id1_0_0_, teacher0_.email as email2_0_0_, teacher0_.name as name3_0_0_, teacher0_.password as password4_0_0_, teacher0_.sex as sex5_0_0_, teacher0_.username as username6_0_0_ from Teacher teacher0_ where teacher0_.id=? at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:152) at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1426) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:352) at com.sun.proxy.$Proxy9.beginTransaction(Unknown Source) at entity.Teacher.getTeacherById(Teacher.java:276) at entity.Teacher.update(Teacher.java:318) at entity.TestTeacher.update(TestTeacher.java:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 更新操作后 ``` 有說人,老師這怎么看呀,根本抓不住重點。是的,如果把它當成作文來看,當然抓不住重點了。如果抓重點呢? > 只看自己負責的代碼部分的異常。 本著這個思想,我們刪除沒有用的信息后: ``` 更新操作前 Teacher [id=1, name=hello, username=zhangsan, email=zhangsan@yunzhiclub.com, sex=false, password=] org.hibernate.TransactionException: nested transactions not supported at entity.Teacher.getTeacherById(Teacher.java:276) at entity.Teacher.update(Teacher.java:318) at entity.TestTeacher.update(TestTeacher.java:35) ``` 現在異常明朗了。 我們知道,自己先執行了TestTeacher.update, 然后執行了Teacher.update,再然后執行了:eacher.getTeacherById。看來:異常的輸出順序與執行順序正好相反。 把自己的代碼單獨的列出來,最終我們發現,問題出在了Teacher.getTeacherById(Teacher.java:276),我們在控制臺中,單擊跳轉到該行,發現原來是這句:`Transaction transaction = session.beginTransaction();` # BUG產生的原因 報的問題是:nested transactions not supported 好的,報錯行找到了,提示找到了,下面我們開始GOOGLE:nested transactions not supported 如果這4個單詞你有不認識的,那么你在GOOGLE前,首先要做的是,去翻譯這行英文為:不支持事務嵌套使用 能過查詢我們明白了。他的意思好像是這樣。 以下使用正確: ``` 事務開始 事務結束 事務再開始 事務再結束 事務再再再開始 事務再再再結束 ``` 以下使用錯誤: ``` 事務開始 事務開始 事務結束 事務結束 ``` 找到了錯誤,我們再分析代碼。 由于我們在進行session處理里,采用的單例模式。即:張三找我要輔導員,我把王五指定給了他;李四找我要輔導員,我還是給他的王五。 所以,在update中,我們已經開啟了事務,而此時,我們又調用getTeacherById方法,當這個方法再開始事務的時候。就出現事務嵌套,最終引發了上述BUG。 # 引用server層徹底解決bug 知道了上述的原因,就不能解決了。由于在數據實體類的方法中,需要使用事務來保證數據操作的安全性。而每個事務都應該是獨立存在,所以在實體中,不能出現互相調用的情況。為了避免這種情況,同時,又不會造相同的輪子。我們增加一個server來解決這個問題。 ## 重構實體 ``` package entity; ... // 聲明主體 @Entity public class Teacher { public Boolean update() { // 創建會話(這里的session也是會話的意思,我們以前接觸的http中的session,處理的是用戶與服務器的對話) Session session = MysqlJavaee.getCurrentSession(); // 開啟事務(使用緩沖池進行數據庫的連接) Transaction transaction = session.beginTransaction(); // 在這里,必須使用try catch finally語句。來確定會話正常關閉. // 否則,當操作數據庫產生錯誤時,你可能需要重啟mysql服務 try { // 更新 session.update(this); // 提交事務 transaction.commit(); // 捕獲異常 } catch (HibernateException e) { // 如果事務執行異常,則回滾事務 if (null != transaction) { transaction.rollback(); } // 打印異常 e.printStackTrace(); } finally { // 如果session處于開啟狀態,則關閉session if (session.isOpen()) { // 關閉會話 session.close(); } } return true; } ... ``` ### 測試 ``` @Test public void update() { Teacher teacher = Teacher.getTeacherById(1); System.out.println("更新操作前"); System.out.println(teacher.toString()); // 更新 teacher.setName("hello1"); teacher.update(); // 查看結果 teacher = Teacher.getTeacherById(1); System.out.println("更新操作后"); System.out.println(teacher.toString()); } ``` 控制臺: ``` 更新操作前 Teacher [id=1, name=hello, username=zhangsan, email=zhangsan@yunzhiclub.com, sex=false, password=] Hibernate: update Teacher set email=?, name=?, password=?, sex=?, username=? where id=? Hibernate: select teacher0_.id as id1_0_0_, teacher0_.email as email2_0_0_, teacher0_.name as name3_0_0_, teacher0_.password as password4_0_0_, teacher0_.sex as sex5_0_0_, teacher0_.username as username6_0_0_ from Teacher teacher0_ where teacher0_.id=? 更新操作后 Teacher [id=1, name=hello1, username=zhangsan, email=zhangsan@yunzhiclub.com, sex=false, password=] Hibernate: select teacher0_.id as id1_0_0_, teacher0_.email as email2_0_0_, teacher0_.name as name3_0_0_, teacher0_.password as password4_0_0_, teacher0_.sex as sex5_0_0_, teacher0_.username as username6_0_0_ from Teacher teacher0_ where teacher0_.id=? Teacher [id=1, name=hello1, username=zhangsan, email=zhangsan@yunzhiclub.com, sex=false, password=] class entity.Teacher ``` ## 建立server包 我們在src右建,新建一個package,并起名為server ## 建立TeacherServer文件 在package上右建,新建一個class,并起名為TeacherServer,代碼如下: ``` package server; import entity.Teacher; public class TeacherServer { public Boolean update(Teacher newTeacher) { // 獲取數據表數據 Teacher teacher = Teacher.getTeacherById(newTeacher.getId()); // 賦值 teacher.setEmail(newTeacher.getEmail()); teacher.setName(newTeacher.getName()); teacher.setUsername(newTeacher.getUsername()); teacher.setPassword(newTeacher.getPassword()); teacher.setSex(newTeacher.getSex()); // 更新并返回 teacher.update(); return true; } } ``` ### 單元測試 同樣,我們在test目錄中,新建一個package, 命名為server,并新建一個TeacherServerTest測試類. 代碼如下: ``` package server; import org.junit.Test; import entity.Teacher; public class TeacherServerTest { @Test public void update() { Teacher teacher = Teacher.getTeacherById(1); System.out.println("更新操作前"); System.out.println(teacher.toString()); // 更新 teacher = new Teacher(1, "this is zhangsan", "zhangsan", "zhangsan@yunzhiclub.com", false, "123"); TeacherServer.update(teacher); // 查看結果 teacher = Teacher.getTeacherById(1); System.out.println("更新操作后"); System.out.println(teacher.toString()); } } ``` 控制臺: ``` 更新操作前 Teacher [id=1, name=hello1, username=zhangsan, email=zhangsan@yunzhiclub.com, sex=false, password=] Hibernate: select teacher0_.id as id1_0_0_, teacher0_.email as email2_0_0_, teacher0_.name as name3_0_0_, teacher0_.password as password4_0_0_, teacher0_.sex as sex5_0_0_, teacher0_.username as username6_0_0_ from Teacher teacher0_ where teacher0_.id=? Hibernate: update Teacher set email=?, name=?, password=?, sex=?, username=? where id=? Hibernate: select teacher0_.id as id1_0_0_, teacher0_.email as email2_0_0_, teacher0_.name as name3_0_0_, teacher0_.password as password4_0_0_, teacher0_.sex as sex5_0_0_, teacher0_.username as username6_0_0_ from Teacher teacher0_ where teacher0_.id=? 更新操作后 Teacher [id=1, name=this is zhangsan, username=zhangsan, email=zhangsan@yunzhiclub.com, sex=false, password=123] ``` ## 對接C層 Update.java ``` // 該execute方法將被自動調用, 方法的返回類型必須為String public String execute() { // 獲取要編輯的教師,并實例化 Teacher teacher = new Teacher(id, name, username, email, sex, password); // 更新 TeacherServer.update(teacher); return "success"; } ``` ## 集成測試 [http://localhost:8080/javaee/teacher/edit?id=1](http://localhost:8080/javaee/teacher/edit?id=1)輸入信息后提交,并查看控制臺與數據庫. ** 自下節開始,我們開始拋棄在C層中,直接調用entity的方法。改為C調用server,server再調用entity。** > 本節參考官方文檔:[#objectstate-modifying](https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/objectstate.html#objectstate-modifying)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看