Hibernate基于JAP注解开发

1.JPA简介

JPA是Java Persistence API的简称,中文名Java持久层Api,是JDK1.5注解或者Xml描述对象-关系表的映射关系,并将运行期的实体类对象持久化Dao数据库中!
JPA相当于JDBC一样,只是SUN公司提出来的一种数据库持久层解决方案规范!
JPA和Hibernate关系:
Hibernate是JPA的一种实现,JPA只是一种规范!
在这里插入图片描述

  • JDBC和驱动的关系:
    JDBC只是SUN公司定义的一套API规范,驱动(Mysql、Oracle)是把SUN公司定义的JDBC规范实现了!
    在这里插入图片描述

1.1 什么是JPA

JPA由EJB 3.0软件专家组开发,你可以在Web应用、甚至桌面应用中使用。JPA的宗旨是为POJO提供持久化标准规范,由此可见,经过这几年的实践探索,能够脱离容器独立运行,方便开发和测试的理念已经深入人心了。
JPA的总体思想和现有Hibernate、TopLink、JDO等ORM框架大体一致。总的来说,JPA包括以下3方面的技术:JPA的总体思想和现有Hibernate、TopLink、JDO等ORM框架大体一致。总的来说,JPA包括以下3方面的技术:

  • ORM映射元数据
    JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;用注解简化配置文件!
  • API
    用来操作实体对象,执行CRUD操作,框架在后台替代我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。
  • 查询语言 JPQL
    这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。

1.2. JPA和Hibernate的关系

JPA是需要Provider来实现其功能的,Hibernate就是JPA Provider中很强的一个,应该说无人能出其右。从功能上来说,JPA就是Hibernate功能的一个子集。Hibernate 从3.2开始,就开始兼容JPA。Hibernate3.2获得了Sun TCK的JPA(Java Persistence API) 兼容认证。
在这里插入图片描述

2.JPA注解开发步骤

2.1为实体类添加注解

使用Hibernate的方法操作数据,我们利用xml配置文件将持久化类映射到数据库表,通过面向对象的思想,操作对象间接的操作数据库,但是xml配置写起来比较繁琐,那么我们可以使用Hibernate配置JPA注解的方式进行开发,这样简化开发步骤!
在这里插入图片描述
补充: @Column指定实体类变量对应数据库列, name属性指定对应列名,除此之外,在介绍下@Column的其他属性!
在这里插入图片描述
补充其他属性:

  • 临时字段
    @Transient 注解,用于给实体类添加临时属性(临时属性不需要反映到数据库中)
    在这里插入图片描述
    默认值字段
    默认值字段!创建列时添加default修饰
    在这里插入图片描述
  • 示例
@Entity
@Table(name = "t_customer")
public class Customer {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Long id;

	@Column(name = "name")
	private String name;

	@Column(name = "gender")
	private Character gender;

	@Column(name = "age", nullable = true, length = 10, scale = 10, precision = 0)
	private Integer age;

	@Column(name = "level",columnDefinition="nvarchar(20)")
	@ColumnDefault("10")
	private String level;

	@Transient
	private Boolean married;

	public Customer() {
		super();
	}

	public Customer(String name, Character gender, Integer age, String level) {
		super();
		this.name = name;
		this.gender = gender;
		this.age = age;
		this.level = level;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Character getGender() {
		return gender;
	}

	public void setGender(Character gender) {
		this.gender = gender;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getLevel() {
		return level;
	}

	public void setLevel(String level) {
		this.level = level;
	}

	public Boolean getMarried() {
		return married;
	}

	public void setMarried(Boolean married) {
		this.married = married;
	}
}

2.2 修改Hibernate的核心配置文件

添加JPA注解的实体类,需要将类全路径配置到核心配置文件上!
在这里插入图片描述

2.3 测试

	/**
	 * 使用注解
	 */
	@Test
	public void testAnnotation() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		Customer cust1 = new Customer("肖张", '男', 18, "2");
		session.save(cust1);
		tx.commit();
		System.out.println("新增成功~");
	}

3.JPA的主键策略

3.1JPA的主键策略

JPA 主键策略,没有 Hibernate 主键策略丰富,例如:
在这里插入图片描述
其他的策略:
在这里插入图片描述

  • IDENTITY: 利用数据库的自增长的能力。适合 mysql SQLserver 数据自动增长
  • SEQUENCE(序列):利用数据库的序列机制,适合 Oracle
  • TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。不同的JPA实现商生成的表名是不同的,如 OpenJPA生成openjpa_sequence_table表,Hibernate生成一个hibernate_sequences表,而TopLink则生成sequence表。这些表都具有一个序列名和对应值两个字段,如SEQ_NAME和SEQ_COUNT
  • AUTO:自动选择一个最适合底层数据库的主键生成策略。这个是默认选项,即如果只写@GeneratedValue,等价于@GeneratedValue(strategy=GenerationType.AUTO)。

3.2 hibernate的主键策略

如果使用Hibernate对JPA的实现,可以使用Hibernate对主键生成策略的扩展,通过Hibernate的@GenericGenerator实现。
如果不用数字作为表的主键的话,还可以选择用一个不重复的字符串(UUID)作为主键
注意:id的数据类型改成String
在这里插入图片描述

  • 测试
 /**
   * 使用注解
   */
  @Test
  public void testAnnotation() {
  	Session session = HibernateUtil.openSession();
  	Transaction tx = session.beginTransaction();
  	
  	Customer cust1 = new Customer("肖张", '男', 18, "2");
  	cust1.setId(UUID.randomUUID().toString());
  	session.save(cust1);
  	
  	tx.commit();
  	System.out.println("新增成功~");
  }

也可以按照如下配置,在注解中指定要使用的策略生成器,这样测试用例中就不用人工生成uuid了。

	@Id
	//声明一个策略通用生成器,name为"system-uuid",策略strategy为"uuid"。
	@GenericGenerator(name="system-uuid", strategy="uuid")
	//用generator属性指定要使用的策略生成器。
	@GeneratedValue(generator="system-uuid")
	@Column(name="id")
	private String id;
  • 测试
   /**
	 * 使用注解
	 */
	@Test
	public void testAnnotation() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Customer cust1 = new Customer("肖张", '男', 18, "2");
		session.save(cust1);
		
		tx.commit();
		System.out.println("新增成功~");
	}

4.关联关系

重点:使用注解配置关联关系!!

4.1一对多

4.1.1创建订单实体
/**
 * 订单(多方)
 */
@Entity
@Table(name = "t_order")
public class Order {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Long id;

	@Column(name = "orderno")
	private String orderno;

	// 关联客户
	@ManyToOne
	@JoinColumn(name = "cust_id")
	private Customer customer;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getOrderno() {
		return orderno;
	}

	public void setOrderno(String orderno) {
		this.orderno = orderno;
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
}
  • 测试 订单到顾客 N:1
/*
	 * 测试 订单到顾客 N:1
	 */
	@Test
	public void testAnnotation() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		Order order = session.get(Order.class, 1L);
		System.out.println(order);
		Customer customer = order.getCustomer();
		System.out.println(customer);
		tx.commit();
	}
4.1.2 修改客户实体

添加关联订单,这里使用了级联配置
在这里插入图片描述
CascadeType.PRESIST 级联持久化(保存)操作(持久保存拥有方实体时,也会持久保存该实体的所有相关数据。)
CascadeType.REMOVE 级联删除操作(删除一个实体时,也会删除该实体的所有相关数据。)
CascadeType.MERGE 级联更新(合并)操作(将分离的实体重新合并到活动的持久性上下文时,也会合并该实体的所有相关数据。)
CascadeType.REFRESH 级联刷新操作 (只会查询获取操作)
CascadeType.ALL 包含以上全部级联操作

4.1.3修改Hibernate核心配置文件

hibernate.hbm.xml中添加Order的映射
在这里插入图片描述

  • 测试一对多
	/*
	 * 测试 顾客到订单 1:N
	 */
	@Test
	public void testAnnotation1() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		Customer c = session.get(Customer.class, 1);
		System.out.println(c);
		Set<Order> orders = c.getOrders();
		for (Order o : orders) {
			System.out.println(o);
		}
		tx.commit();
	}
4.1.4 测试级联操作
/**
	 * 测试一对多注解
	 */
	@Test
	public void testOneToMany() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();

		Customer cust = new Customer();
		cust.setName("王五3");

		Order o1 = new Order();
		
		o1.setOrderno("201709003");
		cust.getOrders().add(o1);

		o1.setCustomer(cust);
		
		session.save(cust);

		tx.commit();
	}

4.2 多对多

用户和角色是多对多关系!

4.2.1 创建User实体
/**
 * 用户(多方)
 */
@Entity
@Table(name = "t_user")
public class User {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Integer id;

	@Column(name = "user_name")
	private String name;

	// 关联角色
	@ManyToMany(cascade = { CascadeType.ALL })
	// @JoinTable: 用于映射中间表
	// joinColumns: 当前方在中间表的外键字段名称
	// inverseJoinColumns:对方在中间表的外键字段名称
	@JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "role_id", referencedColumnName = "id") })
	private Set<Role> roles = new HashSet<Role>();

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Set<Role> getRoles() {
		return roles;
	}

	public void setRoles(Set<Role> roles) {
		this.roles = roles;
	}

}
4.2.2 创建Role实体
/**
 * 角色(多方)
 */
@Entity
@Table(name = "t_role")
public class Role {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Integer id;
	
	@Column(name = "role_name")
	private String name;

	// 关联用户
	@ManyToMany()
	@JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "role_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id") })
	private Set<User> users = new HashSet<User>();

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Set<User> getUsers() {
		return users;
	}

	public void setUsers(Set<User> users) {
		this.users = users;
	}
}
4.2.3 修改Hibernate核心配置文件

hibernate.hbm.xml中添加User、Role的映射
在这里插入图片描述

4.2.4 测试多对多
 /**
	 * 测试多对多注解
	 */
	@Test
	public void testManyToMany() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();

		User u1 = new User();
		u1.setName("Helen");

		Role r1 = new Role();
		r1.setName("VIP");

		u1.getRoles().add(r1);

		session.save(u1);

		tx.commit();
	}
  • 根据用户查询角色
/**
	 * 测试多对多注解
	 */
	@Test
	public void testManyToMany1() {
		Session session = HibernateUtil.openSession();
		User u = session.get(User.class, 2);
		System.out.println(u);
		Set<Role> roles = u.getRoles();
		for (Role r : roles) {
		  System.out.println(r);	
		}
		session.close();
	}
  • 根据角色查询用户
	/**
	 * 测试多对多注解
	 */
	@Test
	public void testManyToMany2() {
		Session session = HibernateUtil.openSession();
		Role r = session.get(Role.class, 2);
		System.out.println(r);
		Set<User> users = r.getUsers();
		for (User u : users) {
			System.out.println(u);
		}
		session.close();
	}

4.3 一对一(了解)

4.3.1 创建Person实体
@Entity
@Table(name = "t_person")
public class Person {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Integer id;

	@Column(name = "name")
	private String name;

	// 关联身份证
	@OneToOne(mappedBy = "person", cascade = { CascadeType.ALL })
	private Card card;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Card getCard() {
		return card;
	}

	public void setCard(Card card) {
		this.card = card;
	}

}
4.3.2 创建Card实体类
@Entity
@Table(name = "t_card")
public class Card {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Integer id;

	@Column(name = "card_no")
	private String cardno;

	// 关联公民
	@OneToOne
	@JoinColumn(name = "person_id")
	private Person person;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getCardno() {
		return cardno;
	}

	public void setCardno(String cardno) {
		this.cardno = cardno;
	}

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person person) {
		this.person = person;
	}
}
4.3.3 Hibernate核心配置文件

在这里插入图片描述

4.3.4 测试1:1
@Test
	public void testOneToOne() {

		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();

		Person p = new Person();
		p.setName("老王");

		Card c = new Card();
		c.setCardno("44333222");
		
		p.setCard(c);
        c.setPerson(p);
        
		session.save(p);
		
		tx.commit();
	}
  • 根据Person查询card
	@Test
	public void test1() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Person p = session.get(Person.class, 1);
		System.out.println(p);
		
		Card c = p.getCard();
		System.out.println(c);

		tx.commit();
	}
  • 根据Card查询Person
@Test
	public void test2() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
	
		Card c = session.get(Card.class, 1);
		System.out.println(c);
		
		Person p = c.getPerson();
		System.out.println(p);

		tx.commit();
	}

5. 总结

一对一为例:针对 mappedBy 、 @JoinColumn 、 cascade 的总结
外键由谁来维护
1、当关联关系的双方都不配置mappedBy 属性时,那么双方会互相生成外键,并且执行三条sql
两条插入sql,一条额外的维护外键的sql
2、如果有一方配置了mappedBy 属性,那么对方会生成外键
3、mappedBy 和 @JoinColumn 不能配置在同一方中
4、如果配置在同一方中,以mappedBy为准,@JoinColumn失效
5、只能有一方配置 mappedBy inverse=true

级联操作
1、在A设置了级联操作,A就应该被session操作
2、在A方设置了级联操作,B就应该被设置为A的属性
3、如果A中有外键,那么B应该被设置为A的属性,外键才能被填充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

熊猫-IT

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

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

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

打赏作者

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

抵扣说明:

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

余额充值