1、代理主键:使用不具有业务含义的字段做主键。建议使用
2、自然主键:使用具有业务含义的字段做主键
TABLE: 供框架使用。维护一张表,存主键id,并且是下一个id
SEQUENCE:序列。Oracle、db2
IDENTITY:数据库的自增。mysql、sqlserver、db2
AUTO: 就是TABLE
4种策略只支持数值类型的主键
如果要使用字符类型的主键,需要JPA使用Hibernate的主键生成策略
>increment:不推荐使用。自增,框架使用。select max(id) from table,id+1 作为下一个主键
>native: 根据底层数据库来自动选择
>SEQUENCE:序列。Oracle、db2
>IDENTITY:数据库的自增。mysql、sqlserver、db2
>uuid: 随机字符串
>assigned:用户自己提供
一级缓存,是EntityManager级别。提高查询效率
find 方法:先查询一级缓存,如果不存在,去查询数据库,如果有,直接返回。
@Test
public void test3(){
EntityManager entityManager = JPAUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//有一级缓存,第二个find就不会查询数据库
Student student = entityManager.find(Student.class, 1L);
System.out.println(student.getName());
System.out.println("================分隔符=================");
Student student1 = entityManager.find(Student.class,1L);
System.out.println(student1.getName());
System.out.println(student == student1);
transaction.commit();
entityManager.close();
}
快照机制,把缓存数据和数据库数据同步,自动更新数据。
JPA向一级缓存放入数据时,同时复制一份数据放入快照中,当使用commit()方法提交事务时,会使用主键字段的值判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存的内容同步到数据库,并更新快照;如果一致,则不执行update 语句
@Test
public void test4(){
EntityManager entityManager = JPAUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
/**
* 1、查询缓存
* 2、如果没有,查询数据库,如果有直接返回
* 3、查询回来的内容放入缓存
* 4、把查询回来的值放入快照
* 5、返回对象
*/
Student student = entityManager.find(Student.class, 1L);
student.setName("jack");
//有快照机制,就不需要merge操作了
//entityManager.merge(student);
transaction.commit();
entityManager.close();
}
数据库中的表关系:一对一、一对多、多对多
JPA的关系:
第一步:首先确定两张表之间的关系。(如果关系确定错了,后面做的所有操作就都不可能正确。)
第二步:在数据库中实现两张表的关系
第三步:在实体类中描述出两个实体的关系
第四步:配置出实体类和数据库表的关系映射(重点)
实体类关系建立以及映射配置
1、@OneToMany:
作用: 建立一对多的关系映射
属性:
targetEntityClass:指定多的多方的类的字节码
mappedBy:指定从表实体类中引用主表对象的名称。
cascade:指定要使用的级联操作
fetch:指定是否采用延迟加载
orphanRemoval:是否使用孤儿删除
2、@ManyToOne
作用: 建立多对一的关系
属性:
targetEntityClass:指定一的一方实体类字节码
cascade:指定要使用的级联操作
fetch:指定是否采用延迟加载
3、@JoinColumn
作用: 用于定义主键字段和外键字段的对应关系。
属性:
name:指定外键字段的名称
referencedColumnName:指定引用主表的主键字段名称
unique:是否唯一。默认值不唯一
nullable:是否允许为空。默认值允许。
insertable:是否允许插入。默认值允许。
updatable:是否允许更新。默认值允许。
columnDefinition:列的定义信息。
5、操作需求:保存一个客户和2个联系人
操作谁,就在谁的持久化类中配置级联
在@OneToMany 中配置cascade=CascadeType.ALL 级联所有
在实际开发中,级联删除请慎用!
@Entity//告知框架,这是持久化类,必须要写
@Table(name = "cst_customer")//告知框架,类对应的表名
public class Customer {
@Id//指定主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//指明主键生成策略,IDENTITY 对应mysql的自增
@Column(name = "cust_id")//指定属性和字段的映射关系
private Long custId;
@Column(name = "cust_name")
private String custName;
@Column(name = "cust_source")
private String custSource;
@Column(name = "cust_industry")
private String custIndustry;
@Column(name = "cust_level")
private String custLevel;
@Column(name = "cust_address")
private String custAddress;
@Column(name = "cust_phone")
private String custPhone;
//在主表对应的持久化类描述类与类的关系
@OneToMany(targetEntity = LinkMan.class,mappedBy = "customer",cascade = CascadeType.ALL)
private Set<LinkMan> linkManSet = new HashSet<LinkMan>(0);
//get set
}
@Entity
@Table(name = "cst_linkman")
public class LinkMan {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "lkm_id")
private Long lkmId;
@Column(name = "lkm_name")
private String lkmName;
@Column(name = "lkm_gender")
private String lkmGender;
@Column(name = "lkm_phone")
private String lkmPhone;
@Column(name = "lkm_mobile")
private String lkmMobile;
@Column(name = "lkm_email")
private String lkmEmail;
@Column(name = "lkm_position")
private String lkmPosition;
@Column(name = "lkm_memo")
private String lkmMemo;
//在多的一方配置表与表的关系
//referencedColumnName 配置 被引用的字段名
//name 配置 外键的字段名
@ManyToOne
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
private Customer customer;
//get set
}
实体类关系建立以及映射配置
1、@ManyToMany
作用: 用于映射多对多关系
属性: cascade:配置级联操作。
fetch:配置是否采用延迟加载。
2、@JoinTable
作用: 针对中间表的配置
属性: name:配置中间表的名称
joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段
inverseJoinColumn:中间表的外键字段关联对方表的主键字段
3、级联操作:
操作谁,就在谁的持久化类中配置级联
在@ManyToMany 中配置cascade=CascadeType.ALL 级联所有
在实际开发中,级联删除请慎用!
@Entity
public class SysUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="user_id")
private Long userId;
@Column(name="user_name")
private String userName;
//ManyToMany 多对多
//表述类与类的关系,cascade 配置级联操作
@ManyToMany(targetEntity = SysRole.class,mappedBy = "sysUserSet",cascade = CascadeType.ALL)
private Set<SysRole> sysRoleSet = new HashSet<SysRole>(0);
//get set
}
@Entity
public class SysRole {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="role_id")
private Long roleId;
@Column(name="role_name")
private String roleName;
//ManyToMany 多对多
@ManyToMany
//配置中间表的信息
@JoinTable(name = "sys_user_role",
joinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")},
inverseJoinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")})
private Set<SysUser> sysUserSet = new HashSet<SysUser>(0);
//get set
}
对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。
对象导航查询的使用要求是:两个对象之间必须存在关联关系。
框架默认在一端 对 多端的数据使用 【延迟加载】
框架默认在多端 对 一端的数据使用 【立即加载】
在实际应用中,内存是非常重要的。
分别有find 和 getReference
根据已经加载的对象,导航到他的关联对象。两个对象之间必须存在关联关系。
@Test
public void test7(){
EntityManager entityManager = JPAUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
// 参数命名 :name
String jpql = "from Customer where custName like :name";
Query query = entityManager.createQuery(jpql);
query.setParameter("name","%集团%");
List<Customer> list = query.getResultList();
for (Customer customer : list) {
System.out.println(customer.getCustName());
}
transaction.commit();
entityManager.close();
}
@Test
public void testSQL(){
EntityManager entityManager = JPAUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
String sql = "select * from cst_customer";
Query query = entityManager.createNativeQuery(sql,Customer.class);
List<Customer> list = query.getResultList();
for (Customer customer : list) {
System.out.println(customer.getCustName());
}
transaction.commit();
entityManager.close();
}
@Test
public void testQBC(){
EntityManager entityManager = JPAUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//criteriaBuilder 生成条件 where后面的内容
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
//criteriaQuery 生成sql from Customer where custName like ? and custId = ?
CriteriaQuery<Customer> criteriaQuery = criteriaBuilder.createQuery(Customer.class);
//root 封装谁 就代表谁
Root<Customer> root = criteriaQuery.from(Customer.class);
//生成条件,custName like ?
Predicate p1 = criteriaBuilder.like(root.get("custName").as(String.class), "%集团%");
//生成条件,custId = ?
Predicate p2 = criteriaBuilder.equal(root.get("custId").as(Long.class), 2L);
//生成条件,and
Predicate p3 = criteriaBuilder.and(p1, p2);
criteriaQuery.where(p3);
List<Customer> resultList = entityManager.createQuery(criteriaQuery).getResultList();
for (Customer customer : resultList) {
System.out.println(customer.getCustName());
}
transaction.commit();
entityManager.close();
}