<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 【第八章】 對ORM的支持 之 8.4 集成JPA ——跟我學spring3 ## 8.4? 集成JPA JPA全稱為Java持久性API(Java Persistence API),JPA是Java EE 5標準之一,是一個ORM規范,由廠商來實現該規范,目前有Hibernate、OpenJPA、TopLink、EclipseJPA等實現。 ### 8.4.1? 如何集成 Spring目前提供集成Hibernate、OpenJPA、TopLink、EclipseJPA四個JPA標準實現。 Spring通過使用如下Bean進行集成JPA(EntityManagerFactory): * **LocalEntityManagerFactoryBean:**適用于那些僅使用JPA進行數據訪問的項目,該FactoryBean將根據JPA PersistenceProvider自動檢測配置文件進行工作,一般從“META-INF/persistence.xml”讀取配置信息,這種方式最簡單,但不能設置Spring中定義的DataSource,且不支持Spring管理的全局事務,而且JPA 實現商可能在JVM啟動時依賴于VM agent從而允許它們進行持久化類字節碼轉換(不同的實現廠商要求不同,需要時閱讀其文檔),不建議使用這種方式; persistenceUnitName:指定持久化單元的名稱; 使用方式: ``` <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="persistenceUnit"/> </bean> ``` * **從JNDI中獲取:**用于從Java EE服務器獲取指定的EntityManagerFactory,這種方式在進行Spring事務管理時一般要使用JTA事務管理; 使用方式: ``` <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"> <jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/persistenceUnit"/> </beans> ``` 此處需要使用“jee”命名標簽,且使用&lt;jee:jndi-lookup&gt;標簽進行JNDI查找,“jndi-name”屬性用于指定JNDI名字。 * **LocalContainerEntityManagerFactoryBean:**適用于所有環境的FactoryBean,能全面控制EntityManagerFactory配置,如指定Spring定義的DataSource等等。 **persistenceUnitManager**:用于獲取JPA持久化單元,默認實現DefaultPersistenceUnitManager用于解決多配置文件情況 **dataSource**:用于指定Spring定義的數據源; **persistenceXmlLocation**:用于指定JPA配置文件,對于對配置文件情況請選擇設置persistenceUnitManager屬性來解決; **persistenceUnitName**:用于指定持久化單元名字; **persistenceProvider**:用于指定持久化實現廠商類;如Hibernate為org.hibernate.ejb.HibernatePersistence類; **jpaVendorAdapter**:用于設置實現廠商JPA實現的特定屬性,如設置Hibernate的是否自動生成DDL的屬性generateDdl;這些屬性是廠商特定的,因此最好在這里設置;目前Spring提供HibernateJpaVendorAdapter、OpenJpaVendorAdapter、EclipseLinkJpaVendorAdapter、TopLinkJpaVendorAdapter、OpenJpaVendorAdapter四個實現。其中最重要的屬性是“**database**”,用來指定使用的數據庫類型,從而能根據數據庫類型來決定比如如何將數據庫特定異常轉換為Spring的一致性異常,目前支持如下數據庫(**DB2、DERBY、H2、HSQL、INFORMIX、MYSQL、ORACLE、POSTGRESQL、SQL_SERVER、SYBASE**)。 **jpaDialect**:用于指定一些高級特性,如事務管理,獲取具有事務功能的連接對象等,目前Spring提供HibernateJpaDialect、OpenJpaDialect 、EclipseLinkJpaDialect、TopLinkJpaDialect、和DefaultJpaDialect實現,注意DefaultJpaDialect不提供任何功能,因此在使用特定實現廠商JPA實現時需要指定JpaDialect實現,如使用Hibernate就使用HibernateJpaDialect。當指定**jpaVendorAdapter屬性時可以不指定jpaDialect,會自動設置相應的JpaDialect實現;** **jpaProperties和jpaPropertyMap**:指定JPA屬性;如Hibernate中指定是否顯示SQL的“hibernate.show_sql”屬性,對于jpaProperties設置的屬性自動會放進jpaPropertyMap中; loadTimeWeaver:用于指定LoadTimeWeaver實現,從而允許JPA 加載時修改相應的類文件。具體使用得參考相應的JPA規范實現廠商文檔,如Hibernate就不需要指定loadTimeWeaver。 接下來學習一下Spring如何集成JPA吧: **1、準備jar包,從下載的hibernate-distribution-3.6.0.Final包中獲取如下Hibernate需要的jar包從而支持JPA:** + lib\jpa\hibernate-jpa-2.0-api-1.0.0.Final.jar //用于支持JPA **2、對象模型定義,此處使用UserModel2:** ``` package cn.javass.spring.chapter8; //省略import @Entity @Table(name = "test") public class UserModel2 { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; @Column(name = "name") private String myName; //省略getter和setter } ``` 注意此處使用的所有注解都是位于javax.persistence包下,如使用@org.hibernate.annotations.Entity 而非@javax.persistence. Entity將導致JPA不能正常工作。 **1、?JPA配置定義(chapter8/persistence.xml),定義對象和數據庫之間的映射:** ``` <?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL"/> </persistence> ``` 在JPA配置文件中,我們指定要持久化單元名字,和事務類型,其他都將在Spring中配置。 **2、?數據源定義,此處使用第7章的配置文件,即“chapter7/applicationContext-resources.xml”文件。** **3、?EntityManagerFactory配置定義(chapter8/applicationContext-jpa.xml):** ``` <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="persistenceXmlLocation" value="chapter8/persistence.xml"/> <property name="persistenceUnitName" value="persistenceUnit"/> <property name="persistenceProvider" ref="persistenceProvider"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> <property name="jpaDialect" ref="jpaDialect"/> <property name="jpaProperties"> <props> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean> <bean id="persistenceProvider" class="org.hibernate.ejb.HibernatePersistence"/> ``` ``` <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="generateDdl" value="false" /> <property name="database" value="HSQL"/> </bean> <bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/> ``` * **LocalContainerEntityManagerFactoryBean:**指定使用本地容器管理EntityManagerFactory,從而進行細粒度控制; * **dataSource**屬性指定使用Spring定義的數據源; * **persistenceXmlLocation**指定JPA配置文件為chapter8/persistence.xml,且該配置文件非常簡單,具體配置完全在Spring中進行; * **persistenceUnitName**指定持久化單元名字,即JPA配置文件中指定的; * **persistenceProvider**:指定JPA持久化提供商,此處使用Hibernate實現HibernatePersistence類; * **jpaVendorAdapter**:指定實現廠商專用特性,即generateDdl= false表示不自動生成DDL,database= HSQL表示使用hsqldb數據庫; * **jpaDialect**:如果指定jpaVendorAdapter此屬性可選,此處為HibernateJpaDialect; * **jpaProperties**:此處指定“hibernate.show_sql =true”表示在日志系統debug級別下將打印所有生成的SQL。 **4、?獲取EntityManagerFactory:** ``` package cn.javass.spring.chapter8; //省略import public class JPATest { private static EntityManagerFactory entityManagerFactory; @BeforeClass public static void setUpClass() { String[] configLocations = new String[] { "classpath:chapter7/applicationContext-resources.xml", "classpath:chapter8/applicationContext-jpa.xml"}; ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations); entityManagerFactory = ctx.getBean(EntityManagerFactory.class); } } ``` 此處我們使用了chapter7/applicationContext-resources.xml定義的“dataSource”數據源,通過ctx.getBean(EntityManagerFactory.class)獲取EntityManagerFactory。 5、? 通過EntityManagerFactory獲取EntityManager進行創建和刪除表: ``` @Before public void setUp() throws SQLException { //id自增主鍵從0開始 String createTableSql = "create memory table test" + "(id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " + "name varchar(100))"; executeSql(createTableSql); } @After public void tearDown() throws SQLException { String dropTableSql = "drop table test"; executeSql(dropTableSql); } private void executeSql(String sql) throws SQLException { EntityManager em = entityManagerFactory.createEntityManager(); beginTransaction(em); em.createNativeQuery(sql).executeUpdate(); commitTransaction(em); closeEntityManager(em); } private void closeEntityManager(EntityManager em) { em.close(); } private void rollbackTransacrion(EntityManager em) throws SQLException { if(em != null) { em.getTransaction().rollback(); } } private void commitTransaction(EntityManager em) throws SQLException { em.getTransaction().commit(); } private void beginTransaction(EntityManager em) throws SQLException { em.getTransaction().begin(); } ``` 使用EntityManagerFactory創建EntityManager,然后通過EntityManager對象的createNativeQuery創建本地SQL執行創建和刪除表。 **6、?使用EntityManagerFactory獲取EntityManager對象進行持久化數據:** ``` @Test public void testFirst() throws SQLException { UserModel2 model = new UserModel2(); model.setMyName("test"); EntityManager em = null; try { em = entityManagerFactory.createEntityManager(); beginTransaction(em); em.persist(model); commitTransaction(em); } catch (SQLException e) { rollbackTransacrion(em); throw e; } finally { closeEntityManager(em); } } ``` 使用**EntityManagerFactory**獲取**EntityManager**進行操作,看到這還能忍受冗長的代碼和事務管理嗎?Spring同樣提供JpaTemplate模板類來簡化這些操作。 大家有沒有注意到此處的模型對象能自動映射到數據庫,這是因為Hibernate JPA實現默認自動掃描類路徑中的@Entity注解類及*.hbm.xml映射文件,可以通過更改Hibernate JPA屬性“hibernate.ejb.resource_scanner”,并指定org.hibernate.ejb.packaging.Scanner接口實現來定制新的掃描策略。 ### 8.4.2? 使用JpaTemplate JpaTemplate模板類用于簡化事務管理及常見操作,類似于JdbcTemplate模板類,對于復雜操作通過提供JpaCallback回調接口來允許更復雜的操作。 接下來示例一下JpaTemplate的使用: **1、修改Spring配置文件(chapter8/applicationContext-jpa.xml),添加JPA事務管理器:** ``` <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> ``` * txManager:指定事務管理器,JPA使用JpaTransactionManager事務管理器實現,通過entityManagerFactory指定EntityManagerFactory;用于支持Java SE環境的**JPA擴展的持久化上下文(EXTENDED Persistence Context)**。 **2、修改JPATest類,添加類變量ctx,用于后邊使用其獲取事務管理器使用:** ``` package cn.javass.spring.chapter8; public class JPATest { private static EntityManagerFactory entityManagerFactory; private static ApplicationContext ctx; @BeforeClass public static void beforeClass() { String[] configLocations = new String[] { "classpath:chapter7/applicationContext-resources.xml", "classpath:chapter8/applicationContext-jpa.xml"}; ctx = new ClassPathXmlApplicationContext(configLocations); entityManagerFactory = ctx.getBean(EntityManagerFactory.class); } } ``` **3)JpaTemplate模板類使用:** ``` @Test public void testJpaTemplate() { final JpaTemplate jpaTemplate = new JpaTemplate(entityManagerFactory); final UserModel2 model = new UserModel2(); model.setMyName("test1"); PlatformTransactionManager txManager = ctx.getBean(PlatformTransactionManager.class); new TransactionTemplate(txManager).execute( new TransactionCallback<Void>() { @Override public Void doInTransaction(TransactionStatus status) { jpaTemplate.persist(model); return null; } }); String COUNT_ALL = "select count(*) from UserModel"; Number count = (Number) jpaTemplate.find(COUNT_ALL).get(0); Assert.assertEquals(1, count.intValue()); } ``` * **jpaTemplate**:可通過new JpaTemplate(entityManagerFactory)方式創建; * **txManager:**通過ctx.getBean(PlatformTransactionManager.class)獲取事務管理器; * **TransactionTemplate:**通過new TransactionTemplate(txManager)創建事務模板對象,并通過execute方法執行TransactionCallback回調中的doInTransaction方法中定義需要執行的操作,從而將由模板類通過txManager事務管理器來進行事務管理,此處是調用jpaTemplate對象的persist方法進行持久化; * **jpaTemplate.persist()**:根據JPA規范,在JPA擴展的持久化上下文,該操作必須運行在事務環境,還有persist()、 merge()、remove()操作也必須運行在事務環境; * **jpaTemplate.find():**根據JPA規范,該操作無需運行在事務環境,還有find()、getReference()、 refresh()、detach()和查詢操作都無需運行在事務環境。 此實例與Hibernate和Ibatis有所區別,通過JpaTemplate模板類進行如持久化等操作時必須有運行在事務環境中,否則可能拋出如下異常或警告: * **“javax.persistence.TransactionRequiredException:Executing an update/delete query”**:表示沒有事務支持,不能執行更新或刪除操作; * **警告“delaying identity-insert due to no transaction in progress”:**需要在日志系統啟動debug模式才能看到,表示在無事務環境中無法進行持久化,而選擇了延遲標識插入。 以上異常和警告是沒有事務造成的,也是最讓人困惑的問題,需要大家注意。 ### 8.4.3? 集成JPA及最佳實踐 類似于JdbcDaoSupport類,Spring對JPA也提供了JpaDaoSupport類來支持一致的數據庫訪問。JpaDaoSupport也是DaoSupport實現: 接下來示例一下Spring集成JPA的最佳實踐: **1、?定義Dao接口,此處使用cn.javass.spring.chapter7.dao. IUserDao:** **2、?定義Dao接口實現,此處是JPA實現:** ``` package cn.javass.spring.chapter8.dao.jpa; //省略import @Transactional(propagation = Propagation.REQUIRED) public class UserJpaDaoImpl extends JpaDaoSupport implements IUserDao { private static final String COUNT_ALL_JPAQL = "select count(*) from UserModel"; @Override public void save(UserModel model) { getJpaTemplate().persist(model); } @Override public int countAll() { Number count = (Number) getJpaTemplate().find(COUNT_ALL_JPAQL).get(0); return count.intValue(); } } ``` 此處注意首先JPA實現放在dao.jpa包里,其次實現類命名如UserJpaDaoImpl,即×××JpaDaoImpl,當然如果自己有更好的命名規范可以遵循自己的,此處只是提個建議。 另外在類上添加了**@Transactional**注解表示該類的所有方法將在調用時需要事務支持,propagation傳播屬性為Propagation.REQUIRED表示事務是必需的,如果執行該類的方法沒有開啟事務,將開啟一個新的事務。 **3、進行資源配置,使用resources/chapter7/applicationContext-resources.xml:** **4、dao定義配置,在chapter8/applicationContext-jpa.xml中添加如下配置:** **4.1、**首先添加tx命名空間用于支持事務: ``` <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> ``` 4.2、為**@Transactional**注解事務開啟事務支持: ``` <tx:annotation-driven transaction-manager="txManager"/> ``` 只為類添加**@Transactional**?注解是不能支持事務的,需要通過&lt;tx:annotation-driven&gt;標簽來開啟事務支持,其中txManager屬性指定事務管理器。 4.3、配置DAO Bean: ``` <bean id="abstractDao" abstract="true"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <bean id="userDao" class="cn.javass.spring.chapter8.dao.jpa.UserJpaDaoImpl" parent="abstractDao"/> ``` 首先定義抽象的abstractDao,其有一個entityManagerFactory屬性,從而可以讓繼承的子類自動繼承entityManagerFactory屬性注入;然后定義userDao,且繼承abstractDao,從而繼承entityManagerFactory注入;我們在此給配置文件命名為applicationContext-jpa.xml表示JPA實現。 **5、最后測試一下吧(cn.javass.spring.chapter8\. JPATest):** ``` @Test public void testBestPractice() { String[] configLocations = new String[] { "classpath:chapter7/applicationContext-resources.xml", "classpath:chapter8/applicationContext-jpa.xml"}; ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations); IUserDao userDao = ctx.getBean(IUserDao.class); UserModel model = new UserModel(); model.setMyName("test"); userDao.save(model); Assert.assertEquals(1, userDao.countAll()); } ``` 和Spring JDBC框架的最佳實踐完全一樣,除了使用applicationContext-jpa.xml代替了applicationContext-jdbc.xml,其他完全一樣。也就是說,DAO層的實現替換可以透明化。 還有與集成其他ORM框架不同的是JPA在進行持久化或更新數據庫操作時需要事務支持。 ### 8.4.4? Spring+JPA的CRUD Spring+JPA CRUD(增刪改查)也相當簡單,讓我們直接看具體示例吧: ``` @Test public void testCRUD() { PlatformTransactionManager txManager = ctx.getBean(PlatformTransactionManager.class); final JpaTemplate jpaTemplate = new JpaTemplate(entityManagerFactory); TransactionTemplate tansactionTemplate = new TransactionTemplate(txManager); tansactionTemplate.execute(new TransactionCallback<Void>() { @Override public Void doInTransaction(TransactionStatus status) { UserModel model = new UserModel(); model.setMyName("test"); //新增 jpaTemplate.persist(model); //修改 model.setMyName("test2"); jpaTemplate.flush();//可選 //查詢 String sql = "from UserModel where myName=?"; List result = jpaTemplate.find(sql, "test2"); Assert.assertEquals(1, result.size()); //刪除 jpaTemplate.remove(model); return null; } }); } ``` * 對于增刪改必須運行在事務環境,因此我們使用TransactionTemplate事務模板類來支持事務。 * 持久化:使用JpaTemplate 類的persist方法持久化模型對象; * 更新:對于持久化狀態的模型對象直接修改屬性,調用flush方法即可更新到數據庫,在一些場合時flush方法調用可選,如執行一個查詢操作等,具體請參考相關文檔; * 查詢:可以使用find方法執行JPA QL查詢; * 刪除:使用remove方法刪除一個持久化狀態的模型對象。 Spring集成JPA進行增刪改查也相當簡單,但本文介紹的稍微復雜一點,因為牽扯到編程式事務,如果采用聲明式事務將和集成Hibernate方式一樣簡潔。 原創內容,轉載請注明出處【[http://sishuok.com/forum/blogPost/list/0/2500.html](http://sishuok.com/forum/blogPost/list/0/2500.html#7218)】
                  <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>

                              哎呀哎呀视频在线观看