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();