JPA - EntityManager详解

【1】EntityManager介绍

在 JPA 规范中, EntityManager 是完成持久化操作的核心对象。

实体作为普通 Java 对象,只有在调用 EntityManager 将其持久化后才会变成持久化对象。

EntityManager 对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。

其源码如下:

**
 * Interface used to interact with the persistence context.
 *//这里讲述了EntityManager的作用!!!
 * <p> An <code>EntityManager</code> instance is associated with
 * a persistence context. A persistence context is a set of entity
 * instances in which for any persistent entity identity there is
 * a unique entity instance. Within the persistence context, the
 * entity instances and their lifecycle are managed.
 * The <code>EntityManager</code> API is used
 * to create and remove persistent entity instances, to find entities
 * by their primary key, and to query over entities.
 *
 * <p> The set of entities that can be managed by a given
 * <code>EntityManager</code> instance is defined by a persistence
 * unit. A persistence unit defines the set of all classes that are
 * related or grouped by the application, and which must be
 * colocated in their mapping to a single database.
 *
 * @see Query
 * @see TypedQuery
 * @see CriteriaQuery
 * @see PersistenceContext
 *
 * @since Java Persistence 1.0
 */
public interface EntityManager {
//...
}

这里写图片描述


【2】Entity

实体的状态:

新建状态:   新创建的对象,尚未拥有持久性主键;

持久化状态:已经拥有持久性主键并和持久化建立了上下文环境;

游离状态:拥有持久化主键,但是没有与持久化建立上下文环境;

删除状态:  拥有持久化主键,已经和持久化建立上下文环境,但是从数据库中删除。

【3】find方法

find (Class<T> entityClass,Object primaryKey):返回指定的 OID 对应的实体类对象。

第一个参数为被查询的实体类类型,第二个参数为待查找实体的主键值。

如果这个实体存在于当前的持久化环境,则返回一个被缓存的对象;否则会创建一个新的 Entity, 并加载数据库中相关信息;若 OID 不存在于数据库中,则返回一个 null。

实例如下:

public class JPATest {

    private EntityManagerFactory entityManagerFactory;
    private EntityManager entityManager;
    private EntityTransaction transaction;

    @Before
    public void init(){
        entityManagerFactory = Persistence.createEntityManagerFactory("jpa-1");
        entityManager = entityManagerFactory.createEntityManager();
        transaction = entityManager.getTransaction();
        transaction.begin();
    }

    @After
    public void destroy(){
        transaction.commit();
        entityManager.close();
        entityManagerFactory.close();
    }

    //类似于hibernate中session的get方法--先创建
    @Test
    public void testFind(){
        Customer customer = entityManager.find(Customer.class,1);
        System.out.println(customer.getClass().getName());
        System.out.println("-----------------------------------------------");
        System.out.println(customer.toString());
    }

这里写图片描述


如果数据库中没有对应的信息,返回null:

这里写图片描述


【4】getReference方法

getReference (Class<T> entityClass,Object primaryKey):与find()方法类似。

不同的是:如果缓存中不存在指定的 Entity, EntityManager 会创建一个 Entity 类的代理,但是不会立即加载数据库中的信息,只有第一次真正使用此 Entity 的属性才加载,所以如果此 OID 在数据库不存在,getReference() 不会返回 null 值, 而是抛出EntityNotFoundException。

实例如下:

    //类似于hibernate中session的load方法--需要的时候再创建
    @Test
    public void testGetReference(){
        Customer customer = entityManager.getReference(Customer.class, 1);
        // 这里是代理对象 com.atguigu.jpa.helloworld.Customer_$$_javassist_0,容易出现懒加载异常
        System.out.println(customer.getClass().getName());
        System.out.println("-----------------------------------------------");
//      transaction.commit();
//      entityManager.close();
        System.out.println(customer.toString());
    }

这里写图片描述


如果数据库中没有对应的信息,抛出异常:

这里写图片描述


懒加载异常:

这里写图片描述


【5】persist方法

persist (Object entity):用于将新创建的 Entity 纳入到 EntityManager 的管理。该方法执行后,传入 persist() 方法的 Entity 对象转换成持久化状态。

如果传入 persist() 方法的 Entity 对象已经处于持久化状态,则 persist() 方法什么都不做。

如果对删除状态的 Entity 进行 persist() 操作,会转换为持久化状态。

如果对游离状态的实体执行 persist() 操作,可能会在 persist() 方法抛出 EntityExistException(也有可能是在flush或事务提交后抛出)。

实例如下:

    //类似于hibernate中session的save方法,使对象由临时状态变为持久化状态
    //和hibernate的save方法的不通之处:若对象由id,则不能执行持久化insert操作,而会抛出异常
    @Test
    public void testPersist(){
        Customer customer = new Customer();
//      customer.setId(3);
        customer.setAge(11);
        customer.setBirth(new Date());
        customer.setCreatedTime(new Date());
        customer.setEmail("jane@163.com");
        customer.setLastName("jane");
        entityManager.persist(customer);
        System.out.println("-----------------------------------------------");
        System.out.println(customer.toString());
    }

这里写图片描述


如果为entity设置了id,则会抛出异常:

这里写图片描述


【6】remove方法

remove (Object entity):删除实例。

如果实例是被管理的,即与数据库实体记录关联,则同时会删除关联的数据库记录。

代码如下:

    //类似于hibernate中session的delete方法,把对象对应的记录从数据库删除
    //但注意该方法只能移除持久化对象,而hibernate对象的delete方法还可以移除游离对象
    @Test
    public void testRemove(){
        Customer customer = entityManager.find(Customer.class, 2);
        entityManager.remove(customer);
        System.out.println("-----------------------------------------------");
        System.out.println(customer.toString());
    }

这里写图片描述


【7】merge方法

merge (T entity):merge() 用于处理 Entity 的同步。即数据库的插入和更新操作。

原理示意图如下:

这里写图片描述


测试一如下,传入临时对象,无id:

/**
     * 1.若传入的是一个临时对象,则会创建一个新对象,把临时对象的属性复制到新对象中,然后对新对象进行持久化操作
     * 即,新对象将有id,但以前的临时对象没有id
     */
    @Test
    public void testMerge1(){

        Customer customer = new Customer();
        customer.setAge(11);
        customer.setBirth(new Date());
        customer.setCreatedTime(new Date());
        customer.setEmail("jane@163.com");
        customer.setLastName("jane");

        Customer customer2 = entityManager.merge(customer);

        System.out.println("customer#id :"+customer.getId());
        System.out.println("customer2#id :"+customer2.getId());

    }

测试一如下,传入临时对象:

这里写图片描述


测试二如下,传入游离对象,有id且数据库无对应id,EntityManager中无该对象:

这里执行的时插入语句。

这里写图片描述


测试三如下,传入游离对象,有id且数据库有对应id,EntityManager中无该对象:

这里执行的时更新语句。

这里写图片描述


测试四如下,传入游离对象,EntityManager有该对象:

/**
     * 3.若传入的对象是一个游离对象,即对象有OID;
     * em缓存中存在该对象,jpa会把游离对象复制到缓存中的对象,
     * 然后进行更新操作
     * 
     */
    @Test
    public void testMerge3(){

        Customer customer = new Customer();
        customer.setAge(11);
        customer.setBirth(new Date());
        customer.setCreatedTime(new Date());
        customer.setEmail("jane4@163.com");
        customer.setLastName("jane4");

        customer.setId(4);
        System.out.println("customer :"+customer.toString());

        Customer customer2 = entityManager.find(Customer.class, 4);
        System.out.println("customer2 :"+customer2.toString());

        Customer merge = entityManager.merge(customer);
        System.out.println("merge :"+merge.toString());


    }

控制台结果如下:

这里写图片描述


【8】flush方法

顾名思义,强制刷新。同步持久上下文环境,即将持久上下文环境的所有未保存实体的状态信息保存到数据库中。

同流、缓存中的flush方法意义相同,将数据强制输出或更新。

setFlushMode (FlushModeType flushMode):设置持久上下文环境的Flush模式。参数可以取2个枚举

FlushModeType.AUTO 为自动更新数据库实体,
FlushModeType.COMMIT 为直到提交事务时才更新数据库记录。

getFlushMode ():获取持久上下文环境的Flush模式。返回FlushModeType类的枚举值。

示例如下:

    /**
     * ͬ hibernate的 Session 的 flush方法
     */
    @Test
    public void testFlush(){
        Customer customer = entityManager.find(Customer.class, 1);
        System.out.println(customer);

        customer.setLastName("BB");

        entityManager.flush();
    }

控制台输出结果如下:

这里写图片描述


【9】refresh 方法

refresh (Object entity):用数据库实体记录的值更新实体对象的状态,即更新实例的属性值。

即,刷新内存中对象的属性。

示例如下:

/**
     * ͬ hibernate 的 Session 的 refresh 方法. 
     */
    @Test
    public void testRefresh(){
        Customer customer = entityManager.find(Customer.class, 1);

        customer = entityManager.find(Customer.class, 1);

        customer.setAge(100);
        System.out.println(customer.toString());

        entityManager.refresh(customer);

        System.out.println(customer.toString());
    }

控制台输出如下:

这里写图片描述


【10】clear 方法

clear ():清除持久上下文环境,断开所有关联的实体。如果这时还有未提交的更新则会被撤消。


【11】contains方法

判断一个实例是否属于当前持久上下文环境管理的实体。


【12】isOpen方法

判断当前的实体管理器是否是打开状态。


【13】getTransaction

返回资源层的事务对象。

EntityTransaction实例可以用于开始和提交多个事务。


【14】close 方法

关闭实体管理器。之后若调用实体管理器实例的方法或其派生的查询对象的方法都将抛出 IllegalstateException 异常,除了getTransaction 和 isOpen方法(返回 false)。

不过,当与实体管理器关联的事务处于活动状态时,调用 close 方法后持久上下文将仍处于被管理状态,直到事务完成。


【15】createQuery方法

createQuery (String qlString):创建一个查询对象。


【16】createNamedQuery 方法

createNamedQuery (String name):根据命名的查询语句块创建查询对象。参数为命名的查询语句。


【17】createNativeQuery 方法-1

createNativeQuery (String sqlString):使用标准 SQL语句创建查询对象。参数为标准SQL语句字符串。


【18】createNativeQuery 方法-2

createNativeQuery (String sqls, String resultSetMapping):使用标准SQL语句创建查询对象,并指定返回结果集 Map的 名称。

第一次写博客,那是因为我想与大家分享.Net世界.我原来是ASP程序员,与.Net结缘那是在两年多前.第一次接触它,就喜欢上了.哈哈 接着我给大家分享一下我在项目中用到的数据访问层,这个是我用微软网站上得到的DBHepler数据库访问层的一次改编,让它支持实体类和用表达 式的方式生成SQL,而且更关键的是,他是采用参数的方式传值的,这样就避免了SQL的注入啦.. 以下是这个项目的结构 [SuperDAL] ---DbHelper.cs(来自MSDN的数据访问层) ---EntityManager.cs(实体类管理) ---Expressions.cs(实体类表达式查询) ---Expression.cs(实体类表达式) ---OrderByExpressions.cs(排序表达式查询) ---OrderByExpression.cs(排序表达式) ---ObjectValues -------OrderBy.cs(排序枚举类) ---DBManager.cs(数据访问类管理) ---DbParams.cs(数据库访问类参数) ---DataTableExtensions.cs(这个就是顾名思义啦,DataTable传实体类) 在这里最主要介绍的就是EntityManager这个啦,使用方法如下: 有数据库DB的一张表Customs CREATE TABLE [Customs] ( [Name] [varchar] (20) , [Password] [varchar] (20) , [Email] [varchar] (50) , [Phone] [varchar] (11) NULL , [Old] [int] , [Birthday] [DateTime] ) 有个实体类Customs.cs,结构如下: public class Customs { public string Name {get;set;} public string Password {get;set;} public string Email {get;set;} public string Phone {get;set;} public int Old{get;set} public DateTime Brithday {get;set;} } 数据库表与实体Customs结构是一一对应的.有了实体类CUstoms,下面就可以操作实体类跟操作数据库一样的啦,我们新建一个实体类管理类 CustomsManager.cs public class CustomsManager:EntityManager { public Customs GetByName(string name) { //创建表达式Expressions Expressions exps=new Expressions(); //向表达式添加条件 exps.Eq("name",name); //根据条件查询返回实体类 return EM_GetUnique(exps); } public List SearchByName(string name) { //同样像上面一样建立表达式类 Expressions exps=new Expressions(); exps.Like("name",name);//当然,有年朋友会说如果我要姓为"陈"的,那有些人的名字带陈的怎么办,没关系,可以改为 exps.LeftLike ("name",name); //根据条件查询返回实体类 return EM_GetEntity(exps); } /// /// 登录 /// /// 用户名 /// 密码 public List Login(string name,string password) { Expressions exps=new Expressions(); exps.Eq("name",name); exps.Eq("password",password); return EM_GetEntity(exps); } /// /// 选择年龄大于指定岁数的,并按年龄从小到大排序 /// /// 年龄 public List SelectOlder(int old) { Expressions exps=new Expressions(); exps.Gt("old",old); exp.OrderBys.Add("old", OrderBy.Asc); return EM_GetEntity(exps); } /// /// 选择年龄大于小于指定岁数段的,并按年龄从小到大,姓名从字母升序排序 /// /// 年龄 public List SelectByOld(int oldStart,int oldend) { Expressions exps=new Expressions(); exps.Between("old",oldStart,oldEnd); exp.OrderBys.Add("old", OrderBy.Asc); exp.OrderBys.Add("name",OrderBy.Asc); return EM_GetEntity(exps); } #region 增删改 操作 /// /// 更新操作 /// /// 实体类 public int Update(Customs customs) { return EM_Save(customs);//返回更新的记录数,当然,一般成功执行就会返回1;也可以改上面为public void Update(Customs customs) } /// /// 删除操作 /// /// public int DeleteByName(string name) { Expressions exps=new Expressions(); exps.Eq("name",name); return EM_Delete(exps); } /// /// 删除操作 /// /// 实体类 public int Save(Customs custom) { return EM_Save(custom); } #endregion } 当然还有更多的也就不一一贴出来了 Expressions支持的表达式有 1. Eq (等于)[name=value] 2. NotEq (不等于)[not name = value] 3. Ge (大于等于)[name >=value] 4. Gt (大于)[name>value] 5. Le (小于等于)[name<=value] 6. Lt (小于)[name<value] 7. In (包括)[name in (value)] 8. NotIn (不包括)[not name in (value) 9. IsNotNull (不为NULL)[not name is null] 10. IsNull (等于NULL)[name is null] 11. Between (之间)[name between valueStart and valueEnd] 12. Like (模糊) [name like ‘%value%’ ] 13. LeftLike (左模糊) [name like ‘%value’] 14. RightLike (右模糊) [name like ‘value%’] 其它功能待与Net爱好者探讨啦,希望你有更好的思路
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值