持久化API(JPA)系列(四)管理器EntityManager--执行数据库更新


        EntityManager是应用访问持久化上下文中的实体的接口,用来对实体Bean进行操作。我们可以使用它来创建、删除、修改持久化的实体,以体现到数据库中;也可以从数据库中查询得到实体或实体列表。所有的这些操作都是通过实体管理器进行的。
本文将首先讲解EntityManager对象的引用方式,然后讲解使用EntityManager的操作函数实现数据库的各种操作,包括以下内容。

持久化实体persist():往数据表中插入数据。

删除实体remove():从数据表中删除记录。

更新实体merge():更新数据表记录。

刷新实体到数据库flush()。

设置Flush刷新模式setFlushMode()。

刷新实体refresh():从数据表中更新。

按主键查询实体find():从数据表中查询记录。

检测实体是否被管理contains()。

分离管理的实体clear()。

=============================================================================
1、 EntityManager对象的引用方式
根据实体管理器应用的场景不同,可以将它分为两种类型。
1)容器托管的EntityManager
容器托管的EntityManager对象必须在EJB容器中运行,而不能在Web容器和Java SE环境中运行。前一节的实例中的EntityManager对象就是通过注入@PersistenceContext注释从容器中获得的,这种获得EntityManager对象的方式就是容器托管。这种方式使用起来最简单,开发人员不需要考虑EntityManager对象的创建、事务等复杂问题,所有这些都交给容器去管理。取得该对象的方式如下:
@PersistenceContext(unitName="demo")  
EntityManager em; 
2)应用托管的EntityManager
应用托管的EntityManager对象可以在EJB容器中运行,也可以脱离EJB容器,而与任何的Java环境集成,比如说Web容器、Java SE环境等。它需要开发人员手动地控制它的创建、释放、事务等,这些操作都比较复杂。取得该对象的方式如下:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("demo");  
EntityManager em = emf.getEntityManager(); 


因为我们公司的项目是运行在JBoss这个EJB容器中的,因此采用第一种方式来使用它。


==特点:更新并不会立刻同步到数据库=====================================================

1、持久化实体persist()--往数据表中插入数据
DAO层主要的工作就是将EntityManager管理的实体持久化到数据库中保存起来,即将内存中的实体对象写入到数据表中,在表中反应的是新增了一行记录。
持久化的方法是:
em.persist(obj); 
类似于执行了以下SQL语句:
insert into student(name, sex, age, birthday, telephone, address) values('刘中兵', 1, 25, '1981-05-04', '12345678', '北京'); 

2、删除实体remove()--从数据表中删除记录
当需要删除一个已经被持久化到数据库中的实体对象时
Object obj = em.find(clazz, id);  
em.remove(obj); 
例如:
    Student student = em.find(Student.class, 1);  
    em.remove(student);  
类似于执行了以下SQL语句:
delete from student where id=1; 

3、更新实体merge()--更新数据表记录
更新一个已经被持久化的实体对象
Object updatedObj = em.merge(obj); 
例如: 
    Student student = em.find(Student.class, 1);  
    student.setName("liuzhongbing");  
    em.merge(student);  
类似于执行了以下SQL语句:
update student set name="liuzhongbing" where id=1; 

当执行em.merge(student)方法时,有如下两个执行规则:
    如果此时容器中已经存在一个受容器管理的具有相同id的student实例,则容器将会把参数student的内容复制进这个受管理的实例,merge()方法返回受管理的实例,但参数student仍然是分离的、不受管理的。容器在决定Flush时把实例同步到数据库中。
    容器中不存在具有相同id的student实例。容器根据传进的student参数复制出一个受容器管理的student实例,同时merge()方法会返回出这个受管理的实例,但参数student仍然是分离的、不受管理的。容器在决定Flush时把实例同步到数据库中。


==特点:刷新实体同步到数据库=========================================================
1、刷新实体到数据库flush()
当调用persist()、merge()和remove()这些方法时,更新并不会立刻同步到数据库中,直到容器决定刷新到数据库中时才会执行。在默认情况下,容器决定刷新是在"相关查询"执行前或事务提交时发生的,当然"相关查询"除find()和getReference()之外,这两个方法是不会引起容器触发刷新动作的,如果你需要在事务提交之前将更新刷新到数据库中,你可以直接调用EntityManager.flush()方法。在这种情况下,你可以手动来刷新数据库以获得对数据库操作的最大控制。


当实体正在被容器管理时,你可以调用实体的setXXX()方法对数据进行修改,在容器决定Flush时,更新的数据才会同步到数据库中。如果你希望修改后的数据即时同步到数据库中,则可以执行flush()方法:
em. flush(obj); 
该函数将会做两件事:
提交更改的字段到数据库。
刷新数据库中的字段到该实体中。
例如:
    Student student = em.find(Student.class, 1);  
    student.setName("liuzhongbing");  
    em.flush(student);  

这与上面执行merge()的区别如下。
    提交的对象不同:flush()是将容器管理的对象提交到数据库,而merge()不仅可以提交容器管理的对象,而且可以提交没有被容器管理的对象。
    提交的时机不同:flush()会立即同步到数据库,而merge()只会在容器需要Flush时执行同步。

2、设置Flush刷新模式setFlushMode()
上面的flush()函数是手动调用的,如果不手动调用,则只能依赖于容器的自动刷新。在默认情况下容器是自动刷新的,这是因为它对应了刷新了的AUTO值:
public enum FlushModeType {  
    AUTO,  
    COMMIT  

我们可以调用下面的方法改变刷新模式:
em.setFlushMode(FlushModeType.COMMIT); 
这两种模式的区别如下。
AUTO:刷新在查询语句执行前(除了find()和getreference()查询)或事务提交时才发生,适用于在大量更新数据的过程中没有任何查询语句(除了find()和getreference()查询)时执行。
COMMIT:刷新只有在事务提交时才发生,适用于在大量更新数据的过程中存在查询语句(除了find()和getreference()查询)时执行。
这两种模式的区别体现在数据库底层SQL的执行上,即JDBC驱动跟数据库交互的次数。COMMIT模式使更新只在一次网络交互中完成,而AUTO模式可能需要多次交互,它触发了多少次Flush就产生了多少次网络交互。

==特点:获取数据库最新数据,并同步到实体=================================================
1、刷新实体refresh()--从数据表中更新
如果当前被管理的实体已经不是数据库中最新的数据,则可以通过refresh()方法刷新实体,容器会把数据库中的新值重写进实体:
em. refresh(obj); 
例如: 
    Student student = em.find(Student.class, 1);  
    //如果此时student对应的记录在数据库中已经发生了改变,则可以通过refresh()方法得到最新数据:
    em. refresh(student);  


==特点:从实体中查询数据=========================================================
1、按主键查询实体find()--从数据表中查询记录
一旦将对象持久化到数据库中,它就会产生一个主键,我们可以通过这个主键来查询它。查询的方法很简单,只需要指定要查询的id和查询后对象的实体类,就可以取得该记录的实例。
Object obj = em.find(clazz, id); 
其中clazz为实体Bean的类名。
还有一个方法getReference(),用法与find()方法相同,不同的是当数据库中没有找到记录时,该方法将会抛出异常不同。
例如:
Student student = em.find(Student.class, 1);  
类似于执行了以下SQL语句:
select * from student where id=1; 

==特点:查看、分离被容器管理的实体====================================================
1、检测实体是否被管理contains()
前文中的flush()和merge()分别针对实体是否被容器所管理进行了区分,所谓的被管理,就是实体管理器管理中的实体,没有被管理,就是不在实体管理器容器范围内,即没有经过实体管理器的各种操作函数进行持久化。
实体管理器提供了一个方法contains(),用来检查实体是否被管理。形式如下:
boolean b = em.contains(obj); 
contains()方法使用一个实体作为参数,如果这个实体对象当前正被持久化内容管理,则返回值为true,否则为false。
例如:
    Student student = em.find(Student.class, 1);  
    if (em.contains(person)){  
           //正在被持久化内容管理  
    }else{  
        //已经不受持久化内容管理  
    }  

2、分离管理的实体clear()
当处理了大量的实体后,这些实体都会存在于实体管理器中,这将会消耗大量的内存,使程序运行变慢。如果要减少消耗,则可以使用clear()方法,将正在被管理的实体从持久化内容中分离出来。如下所示:
    em.clear();  
如果调用clear()方法,则之前对实体所做的任何改变都将会被丢失,所以在调用clear()方法之前先调用flush()方法保存更改。


发布了134 篇原创文章 · 获赞 28 · 访问量 53万+
展开阅读全文

大牛帮帮忙!JPA-EntityManager只能查询,不能增删,估计是事务的问题,但不知道怎么改了

03-04

# ApplicationContext.xml <context:property-placeholder location="classpath:config/jpa/jdbc.properties" ignore-resource-not-found="true" ignore-unresolvable="true" /> <aop:aspectj-autoproxy proxy-target-class="true" /> <context:component-scan base-package="hxhz.*"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> <!--配置数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="DriverClass" value="${jdbc.driver}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="initialPoolSize" value="${connection_pools.initial_pool_size}" /> <property name="minPoolSize" value="${connection_pools.min_pool_size}" /> <property name="maxPoolSize" value="${connection_pools.max_pool_size}" /> <property name="maxIdleTime" value="${connection_pools.max_idle_time}" /> <property name="acquireIncrement" value="${connection_pools.acquire_increment}" /> <property name="checkoutTimeout" value="${connection_pools.checkout_timeout}" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="persistenceXmlLocation" value="classpath:config/jpa/persistence.xml" /> <!--加载模型对象实例 --> <property name="persistenceUnitName" value="persistenceUnit" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="true" /> <property name="generateDdl" value="true" /> </bean> </property> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> <prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop> <prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop> <prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.generate_statistics">true</prop> <prop key="hibernate.jdbc.fetch_size">${hibernate.jdbc.fetch_size}</prop> <prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <prop key="hibernate.connection.isolation">2</prop> <prop key="javax.persistence.validation.mode">none</prop> <prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider </prop> </props> </property> </bean> <!--添加配置文件 --> <bean id="config" class="hxhz.util.common.CustomizedPropertyConfig"> <property name="location" value="classpath:sys.properties" /> </bean> <bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <!--事务 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"> </bean> <aop:config> <aop:pointcut id="businessService" expression="execution(* hxhz.*.service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="businessService" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" propagation="SUPPORTS" read-only="true" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> </tx:attributes> </tx:advice> # persostence.xml <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL"> <class>hxhz.model.entry.Address</class> <class>hxhz.model.entry.Developlog</class> # DAO @Repository("testbankDaoImpl") public class TestbankDaoImpl extends BaseDaoImpl<TestBank, Long> implements TestbankDao { public boolean addTestbank(TestBank testBank) { try { entityManager.persist(testBank); return true; } catch (Exception e) { e.printStackTrace(); return false; } } # BaseDao @Repository("baseDaoImpl") public class BaseDaoImpl<T, ID extends Serializable> implements BaseDao<T, ID> { @PersistenceContext(unitName="persistenceUnit") protected EntityManager entityManager; public void setEntityManagerFactory(EntityManager entityManager) { this.entityManager = entityManager; } @Autowired private JpaTemplate jpaTemplate; @Autowired private JdbcTemplate jdbcTemplate; private Class<T> entityClass; 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览