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

JPA学习笔记

程序员文章站 2022-04-22 08:01:17
...

JPA学习笔记

JPA是一种规范,而Hibernate,EclipseLink,OpenJPA都是它的一种实现。Spring Data JPA 是简化JPA的写法的实现,封装常用的写法。

一、基本知识

1. JPA规范要求在类路径的META-INF目录下放置persistence.xml,文件的名称是固定的

<!-- src/main/resources/META-INF/persistence.xml -->
    <persistence 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"  
        version="1.0">  
        <persistence-unit name="testdb" transaction-type="RESOURCE_LOCAL">  
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <class>com.domain.entity.User</class>
            <class>com.domain.entity.Role</class>
            <properties>
            <!--  
            <property name="hibernate.connection.driver_class" value="org.gjt.mm.mysql.Driver" />  
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8" />  
            <property name="hibernate.connection.username" value="root" />  
            <property name="hibernate.connection.password" value="123456" />  
            -->
            <property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.EhCacheRegionFactory" />
            <property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" />
            <property name="hibernate.cache.use_second_level_cache" value="true" />
            <property name="hibernate.cache.use_structured_entries" value="true" />
            <property name="hibernate.cache.use_query_cache" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.generate_statistics" value="false" />
            <property name="hibernate.jdbc.fetch_size" value="64" />
            <property name="hibernate.jdbc.batch_size" value="32" />
            <!--<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />  -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect" />
            <property name="hibernate.format_sql" value="false" />
             <property name="hibernate.show_sql" value="true" />  
             <!-- <property name="hibernate.max_fetch_depth" value="1" /> -->
            <property name="javax.persistence.validation.group.pre-persist" value="javax.validation.groups.Default" />
            <property name="javax.persistence.validation.group.pre-update" value="javax.validation.groups.Default" />                
            </properties>  
        </persistence-unit>  
    </persistence>  

2. JPA ORM映射元素数据有XML和注解两种方式

1)在实体bean中用注解@Entity来指定实体以让jpa知道生成数据库中的表
2)在实体bean中用注解@Column(length,nullable,name)指定数据库中的表的字段的长度,是否为空即字段的名字
3)在实体类的前面用注解@Table(name="xx")指定生成表的名字
4)在实体类中用注解@Temporal(TemporalType.Date)指定生日的时间类型
5) @Enumerated(EmumType.STRING//保存到数据库中是索引还是字符串)注解指定枚举类型
6) @Lob声明属性对应的数据库字段为大文本类型,可以存放大的数据(文本和字节)
7) @Transient不成为持久化字段及不跟数据库中的字段形成映射
8) @Basic(fetch=FetchType.LAZY)//是否把数据装载到内存中延迟初始化,第一次访问的时候在加载数据,一般用在大数据存放
9) @Embeddable指定联合组键
一个实体类要在多个不同的实体类中进行使用,而本身又不需要独立生成一个数据库表,就需要使用@Embedded、@Embeddable

@MappedSuperclass
public class IDEntity implements java.io.Serializable{
    @Id
    @GeneratedValue
    private Integer id;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="create_date", updatable=false)
    public Date createDate; 
}

@Entity
@Table(name="city")
public class City extends IDEntity{}

@Entity
@Table(name="brand",uniqueConstraints = { @UniqueConstraint(columnNames = {"mobile_brand", "mobile_model"})})
public class Brand extends  IDEntity {
    @Column(name = "mobile_brand")
    public String brand;
    
    @Column(name = "mobile_model")
    public String model;

    @ManyToOne
    @NotFound(action=NotFoundAction.IGNORE)
    private City city;

    @Column(name="frequency",columnDefinition="INT(11) DEFAULT 0  NULL  COMMENT '请求频率'")
    private int frequency;

    @Transient
    private ChannelParameter channelParameter;

    @OneToOne(mappedBy = "channel",fetch = FetchType.LAZY)
    private ChannelParameter channelParameter;

    @Lob  
    @Basic(fetch = FetchType.LAZY)  
    @Column(columnDefinition = "TEXT",name = "content")
    private String content;
}

3. JPA的增删改查:

1)读取数据不要开启事务,只要有更改数据的动作才需要开启事务
2)增加数据:em.persist(new Person("Jack"));//插入
3)删除数据:em.remove(person); //删除(注意有外键约束时,需要先解除外键约束才能删除)
4)更新数据:

方法一:  
Person person = em.find(Person.class,1);  
person.setName("Jack");(1).跟事务关联在一起了(2)对象处于托管状态  
方法二:  
Person person = em.find(Person.class,1);  
em.clear();//把实体管理器中的所有实体变成游离状态  
person.setName("Jack");//现在还是不可以,实体还是处于游离状态  
em.merge(person);//把游离状态中的实体bean同步到数据库  

5) 查看数据:

方法一:  
Person person = em.find(Person.class,1);//查看数据,1为对象在数据库中的id值  
方法二:  
Person person = em.getReference(Person.class,1);//没有值不出现异常,只person.getName()的时候报异常  
em.refresh(person);//进行数据库刷新,拿出最新的数据  

//加排它锁
person = em.find(Person.class,person.getId(),LockModeType.PESSIMISTIC_WRITE);

4.JPA中四种数据库状态:

(1)新建:刚new出对象来的时候
(2)托管:从数据库中查出来的时候
(3)游离(即脱管)
(4)删除

5.JPA的查询语句:

Query query = em.createQuery("select o from Person o");//必须有select o,id=等于后面不要直接写值以免sql注入
(1)匿名查询用:id
(2)未参数查询?1即:where o.id=?1//指明?的值从索引1开始
uery.getSingleResult

5.1.Java简单的示例代码

EntityManagerFactory factory = Persistence.createEntityManagerFactory("testdb");  
EntityManager em = factory.createEntityManager();  
em.getTransaction().begin();  
em.persist(new User("Jack"));  
em.getTransaction().commit();  
em.close();  
factory.close();  

5.2 JPA提供以下3种查询结果解释方法:

Transformers.ALIAS_TO_ENTITY_MAP //把输出结果转换成map   
Transformers.TO_LIST //把结果按顺序排进List   
Transformers.aliasToBean(target) //把结果通过setter方法注入到指定的对像属性中   
在JPA中Transformers的所有转换都是需要实现ResultTransformer接口。

① ALIAS_TO_ENTITY_MAP :太简单了就是把key和value直接转换到Map当中 :

public Object transformTuple(Object[] tuple, String[] aliases) {   
    Map result = new HashMap(tuple.length);   
    for ( int i=0; i<tuple.length; i++ ) {   
        String alias = aliases[i];   
        if ( alias!=null ) {   
            result.put( alias, tuple[i] );   
        }   
    } 
 
    return result;   
}  

② TO_LIST:转换过程很简单,就是把value转换成List对像:

public Object transformTuple(Object[] tuple, String[] aliases) {   
    return Arrays.asList( tuple );   
}  

③ aliasToBean:转换过程就是通过读取查询后的字段,然后通过使用setter方法注入到目标对像中 :

getSession().beginTransaction(); 
Query query = getSession().createSQLQuery("select * from user"); 
list =query.setResultTransformer(Transformers.aliasToBean(User.class)).list(); 
getSession().getTransaction().commit(); 

参考资料