如果我们希望采用数据库的id自增长的方式来生成主键值的话,这时候我们要用到一个注解@GeneratedValue,这注解里面有一些属性,其中一个是策略strategy,生成主键值的方案,JPA里没有Hibernate提供的那么多方案,它提供的方案有一下一些:
1) AUTO: JPA自动选择合适的策略,是默认选项;
2) IDENTITY:采用数据库ID自增长的方式来生成主键值,Oracle不支持这种方式;
3) SEQUENCE:通过序列产生主键,通过@SequenceGenerator注解指定序列名,MySql不支持这种方式;
4) TABLE:采用表生成方式来生成主键值,那怎么样生成呢?很简单,表里面通常有两个字段,第一个字段是给它一个名称(就是个列名而已),第二个字段专门用来累加用的,就是说没访问一次这个表呢,那么第二个字段就会累加1,不断累加。就是说你们要得到这个主键值的话,访问这个表,然后update这个表的这个字段,把它累加1之后,然后再把这个值取出来作为主键,再给他赋进去,表生成就是这样。
IDENTITY和SEQUENCE这两种生成方案通不通用啊?对所有数据库。
Oracle数据库默认情况下,不能支持用id自增长方式来生成主键值;
mysql在默认情况下不能支持SEQUENCE序列的方式来生成主键值,所以我们一定要注意我们使用的数据库。
TABLE表生成方式才是通用的,但是这种方式效率并不高,
如果我们开发的应用,我们不可以预测用户到底使用哪种数据库,那么这个时候应该设为哪个值呢?答案是AUTO,就是说由持久化实现产品,来根据你使用的方言来决定它采用的主键值的生成方式,到底是IDENTITY?还是SEQUENCE?还是TABLE? 如果用的是Hibernate,那么它会用IDENTITY这种生成方式来生成主键值。
注意:如果我们把策略strategy设置成@GeneratedValue(strategy=GenerationType.AUTO)的话,AUTO本身就是策略的默认值,我们可以省略掉,就是说简单写成这样@GeneratedValue
@GeneratedValue:主键的产生策略,通过strategy属性指定。默认情况下,JPA自动选择一个最适合底层数据库的主键生成策略,如SqlServer对应identity,MySql对应auto increment。
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/persistence_1_0.xsd" version="1.0"> <persistence-unit name="itcast" transaction-type="RESOURCE_LOCAL"> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" /> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="hibernate.connection.driver_class" value="org.gjt.mm.mysql.Driver" /> <property name="hibernate.connection.username" value="root" /> <property name="hibernate.connection.password" value="456" /> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/itcast? useUnicode=true&characterEncoding=UTF-8" /> </properties> </persistence-unit> </persistence>
package cn.itcast.bean; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Person { private Integer id; private String name; public Person() { //对象是由Hibernate为我们创建的,当我们通过ID来获取某个实体的时候,这个实体给我们返回了 //这个对象的创建是由Hibernate内部通过反射技术来创建的,反射的时候用到了默认的构造函数, //所以这时候必须给它提供一个public的无参构造函数 } public Person(String name) { this.name = name; } @Id @GeneratedValue(strategy=GenerationType.AUTO) //auto是默认值,可不写 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; } }
package junit.test; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import org.junit.BeforeClass; import org.junit.Test; import cn.itcast.bean.Person; public class PersonTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void save(){ //对实体bean进行操作,第一步应该获取什么对象啊? SessionFactory对象 //这里用获取的EntityManagerFactory对象,这可以把它看成跟Hibernate的SessionFactory对象差不多的东西 EntityManagerFactory factory = Persistence.createEntityManagerFactory("itcast"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin();//开启事务 em.persist(new Person("XXXX")); em.getTransaction().commit(); em.close(); factory.close(); //SessionFactory --> Session --> begin事务 } }
session.save(obj);
persist这方法在Hibernate里也存在,Hibernate的作者已经不太推荐大家用save方法,而是推荐大家用persist方法
why? 首先并不是代码上的问题,主要是这个名字上的问题,因为我们把这个ORM技术叫做持久化产品,那么我们对
某个对象持久化,应该叫持久化,而不应该叫保存,所以后来Hibernate的作者推荐用persist方法,这并不是功能的问题, 主要是取名的问题,所以用persist方法也可以
目前数据库表是不存在的,我们采取实体建模的思想,让它根据实体bean来生成数据库表,在persistence.xml里,<property name="hibernate.hbm2ddl.auto" value="update"/>,生成策略是update,就是说表不存在的时候,它会创建数据库表。
问题,它什么时候创建表啊?创建表的时机是在什么时候创建的啊?答案是得到SessionFactory的时候,在JPA里也一样,是我们得到EntityManagerFactory的时候创建表,也就是说我们只要执行这段代码就生成表了。