欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【java框架】JPA(2) -- JPA基础

程序员文章站 2022-05-18 18:08:16
1. JPA核心API对象 1.1.Persistence持久化对象 Persisitence主要用于创建EntityMangerFactory,它可以根据传入的持久化单元名称来创建对应的EntityMangerFactory。 // 对应配置文件里面的persistence-unit name=" ......

1.   jpa核心api对象

1.1.persistence持久化对象

persisitence主要用于创建entitymangerfactory,它可以根据传入的持久化单元名称来创建对应的entitymangerfactory。

// 对应配置文件里面的persistence-unit name="cn.yif.jpa02"
// 通过持久化类创建一个实体类管理工厂
entitymanagerfactory entitymanagerfactory = persistence.createentitymanagerfactory("cn.yif.jpa02");

1.2.entitymangerfactory实体管理工厂

entitymangerfactory是一个线程安全的对象,在一个项目中只需要一个entitymanger对象,对应一个数据库资源,entitymangerfactory对象是一个重量级对象,创建与销毁是比较耗费资源的,其中包含了数据库的配置信息,所有实体及关系,预定义jpql语句、二级缓存。

1.3.entitymanger实体管理对象

entitymanger提供和持久化相关的操作:包括增、删、改、查等,是线程不安全的对象,因此在项目中应该每次只能让一个线程所使用,避免多个线程共享使用。entitymanger是轻量级的,创建与销毁不需要消耗太多的资源,应该用完就关闭。web中对应一次请求,创建一个entitymanger对象。

1.4.transcation事务

分为javax.persistence.entitytransaction与javax.transaction.transaction jta事务两种。

javax.persistence.entitytransaction:只能控制相同一个数据库不同表的事务管理,大多数情况使用这种。

 

javax.transaction.transaction:处理不同数据库不同表的事务管理。tomcat默认不支持jta事务(可以通过插件来解决),或者需要用javaee服务器:如jboss、weblogic服务器。

jta事务使用场景:比如跨行转账、事务列表。

2.   主键生成策略

主键实现有两种类型,分为:自然主键与代理主键。

自然主键:表示把含有业务意义的字段作为主键,一般比如使用身份证号、手机号等作为自然主键,而且此字段必须唯一。

注意:在jpa中不定义@generatedvalue则表示自然主键,在保存之前自己设置主键值。

 

代理主键:主键一般没有任何意义,用来区别每行数据是不同的。

在jpa中提供了四种主键生成的策略:identity、sequence、table、auto。

2.1.identity

identity表示主键自增,jpa配置identity策略时会自动将主键设置为自增+1,具体配置如下:

//@id是必须的注解,表示对应数据库的主键
   @id
   //generatedvalue表示主键生成策略
   //①identity:表示的是自增,
   // 特点:1.主键必须是数值类型;2.使用的数据库必须支持自增功能;3.使用数据库原生的生成策略,性能是很高的
   // 4.支持identity的数据库类型:mysql, sql server, db2, derby, sybase, postgresql
   @generatedvalue(strategy = generationtype.identity)
   private integer id;

2.2.sequence

sequence表示自增方式为序列方式,一般在oracle中使用,一个domain创建一张表,对应一个序列,oracle不支持id自增长列而是使用序列机制生成主键id。

//②sequence:序列
    //特点:1.主键必须是数值类型;2.使用的数据库必须支持序列;3.使用数据库原生的生成策略,性能上是很高的
    //4.会默认去创建一个序列,这个序列的名称叫做:hibernate_sequence,所有domain都默认使用这个序列,id在这个序列基础上自增
    //使用名叫seq特定的序列
    @generatedvalue(strategy = generationtype.sequence,generator = "seq")
    //name:序列生成器的名称,会在@generatedvalue中进行引用
    //sequencename会对应真实数据库中序列的名称oiddomain_sequence,在数据库中创建名称为oiddomain_sequence的序列
    //如果不指定序列生成器的名称sequencename = "oiddomain_sequence",
    //则使用厂商提供的默认序列生成器,比如hibernate默认提供的序列名称为hibernate_sequence
    @sequencegenerator(name = "seq", sequencename = "oiddomain_sequence")
    private integer id;

支持sequence的数据库:oracle、post gresql、db2。

2.3.table

table支持所有的数据库类型,在实际项目中如果前期确定不了数据库,可以使用table。

//③table(高低位)
    //特点:1.主键必须是数值类型;2.支持所有的数据库类型(使用默认的序列);3.性能超级低,每次使用都要进行查询与修改(兼容性牺牲)
    //如果不使用表生成器,会使用默认的表,比如oracle中使用hibernate_sequence
    @tablegenerator(name = "seq", table = "oiddomain_table", pkcolumnname = "sequence_name", valuecolumnname = "sequence_count", initialvalue = 1, allocationsize = 1)
    @generatedvalue(strategy = generationtype.table, generator = "seq")
    private integer id;

2.4.auto

//④auto 自动根据具体的数据库选择合适的策略,可以是table/sequence/identity中的一种
   //假如数据库是oracle,则选择显示配置sequence,不使用默认序列配置
   //假如数据库是mysql,则选择identity
   //如果不特别指定,这是默认的主键生成策略
   @generatedvalue(strategy = generationtype.auto)
    private integer id;

3.   jpa持久对象状态

jpa中有四种持久化对象的状态:临时状态(transient):瞬时状态、持久化状态(persistent):托管状态、游离状态(detached):脱管状态、删除状态(removed)。

临时状态:表示该对象刚刚使用new语句创建,没有和entitymanager发生关系。没有被持久化,不处于entitymanager中。

持久化状态:表示该对象和entitymanager发生了关系,被加入到entitymanager的一级缓存中,一级缓存中有数据了。

游离状态:这个对象和entitymanager解除了关系,已经被持久化,但不处于entitymanager中。

删除状态:调用了entitymanager.remove()方法,对象有关联的id,并且在entitymanager的管理下,可能计划被删除,事务被commit提交后真正删除。

3.1.脏数据更新

脏数据:一个持久化对象在事务管理内,发生在事务访问数据并对数据进行了修改,但还未提交到数据库中,未提交的这个数据就叫做脏数据。

而脏数据在jpa中执行merge时,与是否调用merge方法无关,此时当事务进行提交commit时,会自动更新到数据库中。

@test
    public void jpaupdate() {
        entitymanager entitymanager = jpautil.getentitymanager();
        entitytransaction transaction = entitymanager.gettransaction();
        transaction.begin();
        //从数据库中拿到的对象是一个持久化的对象
        employee employee = entitymanager.find(employee.class, 1);
        employee.setname("修改者哈哈");
        employee.setage(223);
        //执行修改
        //在对象是持久化对象的状态下,用不用merge方法,和修改没有关系,即调用与否,都会向数据库做修改
        //entitymanager.merge(employee);
        //提交的时候会从数据库查询有没有这个employee,如果变更了,就执行merge进行数据更新
        //即commit的时候才执行sql,这个过程叫做脏数据更新(一旦持久化数据对象进行修改,就是脏数据)
        transaction.commit();

        jpautil.close(entitymanager);
}

3.2.脏数据更新执行流程

①    拿到entitymanager对象,开启事务;

②    通过entitymanager对象从数据库中查询到对应的持久化对象,这个对象会放入到一级缓存中,jpa会为当前的这个对象准备一个快照(相当于把这个对象进行一个备份);

③    在提交事务之前,jpa会将当前这个快照对象与数据库中查询到的对象做一个对比,如果相同,就不需要进行修改了,也不会发送对应的merge sql进行修改;如果对比发现不同,那么jpa就会认为现在这个数据是脏数据,脏数据在事务进行提交的时候,发送merge sql语句进行数据库数据的同步。

3.3.persist与merge对比

@test
    public void jpapersistormerge() {
        employee employee = new employee("创建者001", 20);
        entitymanager entitymanager = jpautil.getentitymanager();
        entitytransaction transaction = entitymanager.gettransaction();
        transaction.begin();
        /**
         *  persist:放到方法中的对象会变成持久化对象,改变的是原对象(这个对象就在一级缓存当中)
         */
        entitymanager.persist(employee);
        employee.setname("更新创建者001");
        transaction.commit();
        jpautil.close(entitymanager);
    }

对应会执行两条sql语句:先发送insert语句,之后发送update语句进行脏数据更新。

【java框架】JPA(2)  -- JPA基础

 

 

@test
    public void jpapersistormerge() {
        employee employee = new employee("创建者001", 20);
        entitymanager entitymanager = jpautil.getentitymanager();
        entitytransaction transaction = entitymanager.gettransaction();
        transaction.begin();
        /**
         *  merge:放到方法中的对象不会变成持久化对象,但是它会返回一个持久化对象,修改持久化对象同样生效
         */
        //entitymanager.persist(employee);
        employee employee1 = entitymanager.merge(employee);
        employee1.setname("更新创建者001");
        transaction.commit();
        jpautil.close(entitymanager);
    }

执行上述操作同样会发送两条sql语句:

【java框架】JPA(2)  -- JPA基础

 

 

3.4.remove的使用

jpa中remove是不是直接删除数据,而是修改一个对象的状态为删除状态,当事务提交commit之后,delelte sql语句才会发送,对应去删除数据中的脏数据。

@test
public void jparemove() {
      entitymanager entitymanager = jpautil.getentitymanager();
      entitytransaction transaction = entitymanager.gettransaction();
      transaction.begin();
      /**
       * remove并不是直接删除数据,而是修改一个持久化对象的状态为删除状态(计划删除)
       * 对应只能有一个entitymanager,其它entitymanager对象的持久化状态在这里是不能使用的
       */
      employee employee = entitymanager.find(employee.class, 7);
      entitymanager.remove(employee);
      transaction.commit();
      jpautil.close(entitymanager);
}