Java 8 Streams 中的数据库 CRUD 操作

澳门新葡亰3522平台游戏 2

创建实体

创建实体的方式非常直接。我们就使用实体生成的实现,把列的值设置好然后持久化到数据源就可以了。

hares.persist(
  new HareImpl()
    .setName("Harry")
    .setColor("Gray")
    .setAge(8)
);

persist 方法会返回一个 (潜在的) Hare
新实例,里面像“id”这种自动生成键已经设置好了。如果我们想在持久化之后继续使用 Harry,
那就可以使用 persist 方法返回的这个:

final Hare harry = hares.persist(
  new HareImpl()
    .setName("Harry")
    .setColor("Gray")
    .setAge(8)
);

 如果持久化操作失败了,例如如果有一个外键违反了唯一性约束,就会有一个
SpeedmentException
抛出。我们应该对此进行检查,如果有默写东西会阻止我们对这条 hare
记录进行持久化,就应该显示一条错误信息。

try {
  final Hare harry = hares.persist(
    new HareImpl()
      .setName("Harry")
      .setColor("Gray")
      .setAge(8)
  );
} catch (final SpeedmentException ex) {
  System.err.println(ex.getMessage());
  return;
}

作用

用于标注主键的生成策略,通过strategy属性指定。默认情况下,JPA自动选择一个最适合底层数据库的主键生成策略:

  • SQL Server:identity
  • MySQL:auto increment

在javax.persistence.GenerationType中定义了以下几种可供选择的策略:

  • IDENTITY:采用数据库ID自增长的方式来自增主键字段,Oracle不支持这种方式
  • AUTO:JPA自动选择合适的策略,是默认选项
  • SEQUENCE:通过序列产生主键,通过@SequenceGenerator注解指定程序名,MySQL不支持这种方式
  • TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植

接触一个新工具的时候,刚开始要克服的最大障碍就是如何让你自己先尝试做出一个小东西来。现在你也许对
Java 8 中新的 Stream API
的运作方式在理解上比较自信,但你也许并没用它来进行过数据库查询操作。为了帮助你开始使用
Stream API 来对 SQL 数据库进行创建、修改和读取操作,
我已经在这个快速开始的教程中把它们整合到了一起。希望它能帮助你提升对流式API的使用水平!

作用

指明日期的表达形式,value属性需要指定TemporalType的枚举值,
TemporalType 的枚举值包括:

  • TemporalType.TIMESTAMP // yyyy-MM-dd HH:mm:ss形式
  • TemporalType.DATE // yyyy-MM-dd形式

生成代码

要在一个 Maven 工程中开始使用 Speedment,需要你将下面几行代码添加到你的
pom.xml 文件中。在本例中,我使用的是 MySQL,而你也可以选择使用
PostgreSQL 或者
MariaDB。面向于像Oracle这样的专有数据库可用于企业级客户。

JPA规范

澳门新葡亰3522平台游戏 1

更新实体

更新存在的实体和读取以及持久化实体非常相似。在我们调用update()方法之前,对实体本地拷贝的改变,不会影响数据库内容。

下面,我们拿到之前使用Hare创建的Harry,并将他的颜色变为棕色:

harry.setColor("brown");
final Hare updatedHarry = hares.update(harry);

如果更新被接受了,那么管理器会返回hare的一个新的拷贝,因为我们在后面会继续使用这个实例。就想做“创建”的例子中,更新可能会失败。也许颜色被定义为“值唯一”,棕色已经存在于hare中。那样的话,会抛出一个SpeedmentException异常.

我们也可以通过合并多个实体到一个流中来同时更新他们。加入我们想将所有名字为Harry的hare变为棕色,我们可以这样做:

hares.stream()
  .filter(Hare.NAME.equal("Harry"))
  .map(Hare.COLOR.setTo("Brown"))
  .forEach(hares.updater()); // 更新流中存在的元素

我们还应该使用try-catch语句来确保在运行过程中有失败发生时警告用户。

try {
  hares.stream()
    .filter(Hare.NAME.equal("Harry"))
    .map(Hare.COLOR.setTo("Brown"))
    .forEach(hares.updater());
} catch (final SpeedmentException ex) {
  System.err.println(ex.getMessage());
  return;
}

EntityManager类

具体实例中讲解

public class Customer {
    private Integer id;
    createTime,birthday,age,lastName,email
    ...
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Id
    public Integer getId(){
        return this.id;
    }
    ...
    toString()...
}

public class JPATest {
    private EntityManager entitymanager;

    private EneityMangerFactory entitymanagerFactory;

    private EntityTransaction transaction;

    @Before
    public void init(){
        entitymanagerFactory = Persistencce.createEntityManagerFactory("jpa-1");
        entitymanager = entitymanagerFactory.createEntityManager();
        transaction = entitymanager.getTransaction();
        transaction.begin();
    }

    // 类似于Hibernate的sessionFactory.get 方法
    // 执行结果特点:1. 打印查询SQL 2. 打印横线 3. 打印查询结果 (未使用懒加载)
    @Test
    public void testFind(){
        Customer customer = entitymanager.find(Customer.class,1); // 数据库中请确保有一条记录
        sysout("-----------------");
        sysout(customer);
    }

    // 类似于Hibernate的sessionFactory.load方法
    // 执行结果特点:1. 打印横线 2. 打印查询SQL 3. 打印查询结果 (使用了懒加载,在查询结果被真正使用时才做查询)
    // 如果在查询结果被真正使用前,关闭了session,调用查询结果时会报session关闭的异常,即:
    //      org.hibernate.LazyInitializationException:could not initialize proxy - no Session
    @Test
    public void testGetReference(){
        Customer customer = entitymanager.getReference(Customer.class,1); // 数据库中请确保有一条记录
        sysout("-----------------");
        sysout(customer);
    }

    // 类似于 hibernate的save方法,使对象由临时状态变为持久化状态。
    // 和hibernate的save方法的不同之处:若对象有id,则不能执行insert操作,而会抛出异常
    @Test
    public void testPersistence(){
        Customer customer = new Customer();
        customer.setAge...;
        customer.setBirthday...
        customer.setCreateTime...
        customer.setEmail...
        customer.setLastName...

        entitymanager.persist(customer);

        sysout(customer.getId());// 能看到id被打印
    }
    // 类似于hibernate的delete方法,把对象对应的记录从数据库中移除
    // 但注意:该方法只能移除持久化对象,但hibernate的delte方法实际上还可以移除游离对象
    @Test
    public void testRemove(){
        // Customer customer = new...;
        // customer.setId(2) ;// 请确保表中有这条数据
        // entitymanager.remove(customer);// 这样做会报错,hibernate.delete可以这样做

        Customer customer2 = entitymanager.find(Customer.class,2);
        entitymanager.remove(customer2);// 这样做就不会报错
    }
    @After
    public void destroy(){
        transaction.commit();
        entitymanager.close();
        entitymanagerFactory.close();
    }
    // 总的来说,类似于hibernate的session的saveOrUpdate方法
    // 会创建一个新的对象,把临时对象的属性复制到新的对象中,然后对新的对象执行持久化操作,
    // 所以新的对象有id,但以前的临时对象中没有id。
    @Test
    public void testMerge1(){
        Customer   c = new Customer()..
        c.setAge...
        c.setBirthday...
        c.setCreateTime new Date....
        c.setEmail...
        c.setLastName...

        Customer c2= entitymanager.merge(c);

        sysout(c.id); // c 不会有id
        sysout(c2.id); // c2 有id,持久化的是c2

    }
    // 若传入的是一个游离对象,即传入的对象有ID。
    // 1. 若在EntityManger 缓存中没有该对象
    // 2. 若在数据库中也没有对应的记 录
    // 3. JPA会创建一个新的对象,然后把当前游离的对象的属性复制到新创建的对象中
    // 4. 对新创建的对象执行insert操作。
    @Test 
    public void testMerge2(){
        Customer   c = new Customer()..
        c.setAge...
        c.setBirthday...
        c.setCreateTime new Date....
        c.setEmail...
        c.setLastName...

        c.setId(100); // 使c变成游离对象

        Customer c2= entitymanager.merge(c);

        sysout(c.id); // 打印100
        sysout(c2.id); // 打印持久化后的值,不一定就是100
    }
    // 若传入的是一个游离对象,即传入的对象有ID。
    // 1. 若在EntityManger 缓存中没有该对象
    // 2. 若在数据库中有对应的记录
    // 3. JPA会查询对应的记录,然后返回该记录对应的对象,再然后会把游离对象的属性复制到查询到的对象中
    // 4. 对查询到的对象执行update操作。
    @Test
    public void testMerge3(){
        Customer   c = new Customer()..
        c.setAge...
        c.setBirthday...
        c.setCreateTime new Date....
        c.setEmail...
        c.setLastName...

        c.setId(4); // 使c变成游离对象 , 确保数据库中存在id=4的对象

        Customer c2= entitymanager.merge(c);

        sysout(c== c2); // false
    }
    // 若传入的是一个游离对象,即传入的对象有ID。
    // 1. 若在EntityManger 缓存中有该对象
    // 2. JPA会把游离对象的属性复制到查询到EntityManager缓存中的对象中
    // 3. EntityManager 缓存中的对象执行UPDATE
    // hibernate中,在缓存中不能存在两个id相同的对象,在hibernate中、
    // Customer c1=....实例化...,确保c1的id=4
    // Customer c2 = entityManager.find(Customer.class,4) ;
    // session.saveOrUpdate(c1); // 这会将c1 加载进缓存,两个id同为4的Customer实例在hibernate中不能存在,会报
    //  org.hibernate.NonUniqueObjectException的错误
    @Test
    public void testMerge4(){
        Customer   c = new Customer()..
        c.setAge...
        c.setBirthday...
        c.setCreateTime new Date....
        c.setEmail...
        c.setLastName...

        c.setId(4); // 使c变成游离对象 , 确保数据库中存在id=4的对象

        Customer c2= entitymanager.find(Customer.class,4); // 确保数据库中存在id=4的对象
        entityManager.merge(customer);

        sysout(c== c2); // false

    }
    // 同hibernate中,session.flush()
    @Test
    public void testFlush(){
        Customer c = entityManager.find(Customer.class,1);//确保数据库中已存在id=1的记录
        sysout(c);
        c.setLastName("cc"); // 在不执行flush方法时:这个值在commit时才执行update的SQL,然后数据会被更新到数据库中
        entityManager.flush(); // 在执行flush方法时:会执行update的SQL,执行commit方法时会更新到数据库中
    }

    // 同hibernate 中 session的refresh方法
    @Test
    public void testRefresh(){
        Customer c = entityManager.find(Customer.class,1);
        c = entityManager.find(Customer.class,1); // 当不执行refresh方法的情况下,只会查询一次,第二次的查询会从
                                            // 缓存中获取
        entityManager.refresh(c); // 当执行refresh方法的情况下,会执行两次查询

    }

在JPA中,实体也有以下几个状态:

  • 新建状态:新创建的对象,尚未拥有持久性主键
  • 持久化状态:已经拥有持久性主键并和持久化建立了上下文环境
  • 游离状态:拥有持久化主键,但是没有与持久化建立上下文环境
  • 删除状态:拥有持久化主键,已经和持久化建立上下文环境,但是从数据库中删除

常用方法:

merge(T entity)

merge()用于处理Entity的同步。即数据库的插入和更新操作 ()

flush()

同步持久上下文环境,即将持久上下文环境的所有未保存实体的状态信息保存到数据库中

setFlushMode(FlushModeType flushMode)

设置持久上下文环境的Flush模式。参数可以取2个枚举

FlushModeType.AUTO自动更新数据库实体,

FlushModeType.COMMIT 直到提交事务时才更新数据库记录

getFlushMode()

获取持久上下文环境的Flush模式。返回 FlushModeType 类的枚举值

refresh(Object entity)

用于数据库实体记录的值更新实体对象的状态,即更新实例的属性值

clear()

清除持久上下文环境,断开所有关联的实体,如果这时还有未提交的更新则会被撤销。

contains(Object entity)

判断一个实例是否属于当前持久上下文环境管理的实体

isOpen()

判断当前的实体管理器是否是打开状态

getTransaction()

澳门新葡亰3522平台游戏,返回资源层的事务对象。EntityTransaction实例可以用于开始和提交多个事务

close()

关闭实体管理器。之后若调用实体管理器实例的方法或其派生的查询对象的方法都将会抛出IllegalstateException异常,除了getTransaction()和isOpen方法返回false。不过,当与实体管理器关联的事务处于活动状态时,调用close方法后持久上下文将处于被管理状态,直到事务完成。

createQuery(String qlString)

创建一个查询对象

createNamedQuery(String name)

根据命名的查询语句查询对象。参数为命名的查询语句

createNativeQuery(String sqlString)

使用标准的SQL语句创建查询对象,参数为标准SQL语句字符串

createNativeQuery(String sql,String resultSetMapping)

使用标准SQL语句创建查询对象,并制定返回结果集Map的名称

初始化 Speedment

当你的域模型生成好了以后,Speedment 的设置就容易了。创建一个新的
Main.java
文件然后添加如下几行代码。你看到的类都是生成的,因此它们的命名都是根据数据库模式、表以及列的名称来决定的。

基础配置

实体删除

我们需要知道的最后一个 CRUD
操作就是从数据库中删除实体。这个操作几乎和“更新”操作时等同的。假如说我们要把年龄超过10岁的兔子的记录都删除,就要这样做:

try {
  hares.stream()
    .filter(Hare.AGE.greaterThan(10))
    .forEach(hares.remover()); // Removes remaining hares
} catch (final SpeedmentException ex) {
  System.err.println(ex.getMessage());
  return;
}

EntityManagerFactory类

作用:创建EntityManager实例

  • createEntityManager(); //
    创建EntityManager的实例,类似于Hibernate的sessionFactory
  • createEntityManager(Map map); //
    用于创建实体管理器对象实例的重载方法,Map参数用于提供EntityManager的属性,不常用
  • isOpen(); //
    检查EntityManagerFactory是否处于打开状态。实体管理器工厂创建后一直处于打开状态,除非调用close方法将其关闭。
  • close(); //
    关闭EntityManagerFactory,关闭后将释放所有资源,isOpen方法测试将返回false,其它方法将不能调用,否则将导致IllegalStateException

Main.java

public class Main {
  public static void main(String... param) {
    final HaresApplication app = new HaresApplicationBuilder()
      .withPassword("password")
      .build();
  }
}

上面的代码创建了一个新的应用程序实体,它使用了一种生成的构造器模式。构造器是的对任何运行时配置细节的设置成为可能,例如数据库的密码。

当我们有了一个应用实体,就可以用它来访问生成的实体管理器了。在这里,我的数据库中有了四个表;
“hare”, “carrot”, “human”, 以及 “friend”.
(你可以在这里找到完整的数据库定义)。

final CarrotManager carrots = app.getOrThrow(CarrotManager.class);
final HareManager hares     = app.getOrThrow(HareManager.class);
final HumanManager humans   = app.getOrThrow(HumanManager.class);
final FriendManager hares   = app.getOrThrow(FriendManager.class);

现在这些实体管理器可以被用来执行所有的CRUD操作了。

JPQL

概述
JPQL:Java Persistence Query
Language,JPQL语言的语句可以是select语句、update语句或delete语句,它们都通过Query接口封装执行

欢迎打赏
澳门新葡亰3522平台游戏 2

总结

通过阅读本文你已经了解了如何在一个 Maven 工程中对 Speedment
进行设置,还有如何使用 Java 8 的 Stream API
来从数据库中创建、更新、读取以及删除实体。这是你可以利用 Speedment
所能进行的操作的一个小的子集,
但已经是一个能让你上手的好的开始了。更多的示例以及更加高级的使用场景可以在 GitHub-page 上找到。

双向多对多关联关系

知识点
在双向多对多关系中,我们必须指定一个关系维护端,可以通过@ManyToMany注解中指定mappedBy属性来标识其关系维护端

必知
商品–类别是一个多对多关系,一个商品可以有多个类别,一个类别下可以有多种商品

步骤
1. 创建商品Item类,配置维护多对多关联关系

@Table(name = "JPA_ITEMS")
@Entity
public class Item implements Serializable {

    private static final long serialVersionUID = 1L;

    private Integer id;

    private String itemName;

    private Set<Category> categrories = new HashSet<>();

    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }

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

    @Column(name = "item_name")
    public String getItemName() {
        return itemName;
    }

    public void setItemName(String itemName) {
        this.itemName = itemName;
    }

    // 使用@ManyToMany注解来映射多对多关联关系
    // 使用@JoinTable来映射中间表
    // 1. name指向中间表的名字
    // 2. joinColumnNames映射当前类所在的表在中间表中的外键
    //   2.1 name指定外键列的列名
    //   2.2 referencedColumnName指定外键列关联当前表的哪一列
    // 3. inverseJoinColumns映射关联的类所在中间表的外键
    //  3.1...3.2...
    @JoinTable(name="ITEM_CATEGORY",
            joinColumns = { @JoinColumn(name = "ITEM_ID", referencedColumnName = "ID") }, 
            inverseJoinColumns = { @JoinColumn(name = "category_id", referencedColumnName = "ID") })
    @ManyToMany()
    public Set<Category> getCategrories() {
        return categrories;
    }

    public void setCategrories(Set<Category> categrories) {
        this.categrories = categrories;
    }
}

2. 创建分类Category类,配置不维护多对多关联关系

@Entity
@Table(name="JPA_CATEGORIES")
public class Category implements Serializable {

    private static final long serialVersionUID = 1L;

    private Integer id;

    private String categoryName;

    private Set<Item> items = new HashSet<>();

    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }

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

    @Column(name="category_name")
    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    @ManyToMany(mappedBy="categrories")
    public Set<Item> getItems() {
        return items;
    }

    public void setItems(Set<Item> items) {
        this.items = items;
    }
}

3. 测试类JPATest

    // 使用维护关联关系的一方获取还是使用不维护关联关系的一方,SQL语句相同(对称)
    @Test
    public void testManyToManyFind2(){
        Category category = entitymanager.find(Category.class, 1);
        sysout(category.getCategoryName());
        sysout(category.getItems().size());
    }


    // 对于关联的集合对象,默认使用懒加载的策略
    @Test
    public void testManyToManyFind(){
        Item item = entitymanager.find(Item.class, 1);
        sysout(item.getItemName());
        sysout(item.getCategrories().size());

    }

    // 多对多的保存
    @Test
    public void testManyToManyPersist(){
        Item i1 = new Item();
        i1.setItemName("i-1");

        Item i2 = new Item();
        i2.setItemName("i-2");

        Category c1=new Category();
        c1.setCategoryName("c-1");
        Category c2=new Category();
        c2.setCategoryName("c-2");

        // 设置关联关系
        i1.getCategrories().add(c1);
        i1.getCategrories().add(c2);

        i2.getCategrories().add(c1);
        i2.getCategrories().add(c2);

        c1.getItems().add(i1);
        c1.getItems().add(i2);

        c2.getItems().add(i1);
        c2.getItems().add(i2);

        // 执行保存
        entitymanager.persist(c1);
        entitymanager.persist(c2);
        entitymanager.persist(i1);
        entitymanager.persist(i2);

    }

背景

Speedment
是一个开放源代码的工具集,它可以被用来生成
Java
实体,并且能将我们同数据库的通信过程管理起来。你可以利用一个图形工具连接到数据库并生成出一套完整的
ORM 框架代码来表示域模型。但是 Speedment
不单单只是一个代码生成器而已,它还是一个能插入应用程序中的运行时程序,这样就有可能将你的
Java 8
流式代码翻译成优化过的SQL查询。这也是我将会在本文中专门讲述的一个部分。

示例

private Date loginTime;

private Date birthday;
// yyyy-MM-dd HH:mm:ss
@Temporal(TemporalType.TIMESTAMP)
public Date getLoginTime(){
    return this.loginTime;
}
public void setLoginTime(Date loginTime){
    this.loginTime=loginTime;
}
// yyyy-MM-dd
@Temporal(TemporalType.DATE)
public Date getBirthday(){
    return this.birthday;
}
public void setBirthday(Date birthday){
    this.birthday=birthday;
}

读取实体

Speedment 运行时中最酷的功能特性就是能够使用 Java 8 的 Stream
API对数据库中的数据进行流式操作。“为什么这样做会很酷呢?” 你可能会这样问你自己。如今甚至Hibernate
都已经支持流式操作了!”这就是回答。

使用 Speedment
流式操作最美好的事情就是它们把构建流的中间和终止动作都考虑进去了。这就意味着如果你在流已经被创建之后添加一个过滤器进去,那么在构建
SQL 语句时这个过滤器也会被考虑进去。

下面是一个示例,我们想要计算数据库中 hare 记录的总数。

final long haresTotal = hares.stream().count();
System.out.format("There are %d hares in total.%n", haresTotal);

这段代码将会生成的SQL查询如下:

SELECT COUNT(id) FROM hares.hare;

这里的终止操作就是 .count() ,因此 Speedment 就知道是要创建一个 SELECT
COUNT(…)
语句。它也知道 “hare”表的主键是“id”这个列,如此就有可能将发送给数据库的整个语句
减少到这个样子。

更加复杂的示例可能就是找出名称以 “rry” 并且年龄大于等于 5
的兔子的数量。这个可以这样写:

final long complexTotal = hares.stream()
  .filter(Hare.NAME.endsWith("rry"))
  .filter(Hare.AGE.greaterOrEqual(5))
  .count();

我们使用由 Speedment
为我们生成的位于构建器来定义过滤器。这使得我们以编程的方式对流进行分析并且将其简化到如下这样一条SQL语句成为可能:

SELECT COUNT(id) FROM hares.hare
WHERE hare.name LIKE CONCAT("%", ?)
AND hare.age >= 5;

如果我们添加了一个 Speedment 不可以对流进行优化的操作, 它就会像一般的
Java 8
流那被处理。我们永远都不会限制生成的位于构建器的使用,它能是流式操作更加的高效。

final long inefficientTotal = hares.stream()
  .filter(h -> h.getName().hashCode() == 52)
  .count();

上述代码会产生一条如下极其低效的语句,但是它仍然可以跑起来。

SELECT id,name,color,age FROM hares.hare;

常用注解

Pom.xml

<properties>
  <speedment.version>3.0.1</speedment.version>
  <db.groupId>mysql</db.groupId>
  <db.artifactId>mysql-connector-java</db.artifactId>
  <db.version>5.1.39</db.version>
</properties>

<dependencies>
  <dependency>
    <groupId>com.speedment</groupId>
    <artifactId>runtime</artifactId>
    <version>${speedment.version}</version>
    <type>pom</type>
  </dependency>

  <dependency>
    <groupId>${db.groupId}</groupId>
    <artifactId>${db.artifactId}</artifactId>
    <version>${db.version}</version>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>com.speedment</groupId>
      <artifactId>speedment-maven-plugin</artifactId>
      <version>${speedment.version}</version>

      <dependencies>
        <dependency>
          <groupId>${db.groupId}</groupId>
          <artifactId>${db.artifactId}</artifactId>
          <version>${db.version}</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

现在你可以访问到许多新的 Maven
资源库,它们能让你更加轻松的使用这个工具包。要启动 Speedment UI,
执行如下命令:

mvn speedment:tool

这样就会有一个过程引导你连接到数据库并对代码生成进行配置。一开始最简单的方法就是用默认的设置先跑起来再说。当你按下生成按钮“Generate,” Speedment
就会对你的数据库元数据进行分析,然后在你的工程中添加像实体和实体管理器这样的类。

用table来生成主键策略

(使用的情景相对较少)

步骤

  1. 配置persistence.xml,persistence.xml位于META-INF目录下
  2. 创建实体类,使用annotation来描述实体类跟数据库表之间的映射关系
  3. 使用JPA API完成数据增删改查操作(EntityManager)

作用

设置每一列的属性

配置persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
    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_2_0.xsd">
    <persistence-unit name="jpa-01">
        <!-- 配置是用什么ORM产品作为JPA的实现 1. 实际上配置的是javax.persistence.spi.PersistenceProvider接口的实现类 
            2. 若JPA项目中只有一个JPA的实现产品,则也可以不配置该节点 -->
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>com.iuie.jpa.entity.Customer</class>

        <properties>
            <!-- 连接数据库的基本信息 -->
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///ns" />
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="123456" />

            <!-- 配置JPA实现产品的基本属性,配置hibernate的基本属性 -->
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>

    </persistence-unit>
</persistence>

概述

JPA:Java Persistence API,用于对象持久化的API
Java EE 5.0平台标准的ORM规范,使得应用程序以统一的方式访问持久层

JPA包括3方面的技术

  1. ORM映射元数据:JPA支持XML和JDK
    5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象
  2. 持久化到数据库表中。
  3. JPA的API:用来操作实体对象,执行CRUD操作,框架在后台完成所有事情,开发者从频繁的JDBC和SQL代码中解脱出来。
  4. 查询语言(JPQL):这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序和具体的SQL紧密耦合。

步骤

·1. 创建一个生成主键的表:

表名:JPA_ID_GENERATOR(数据表ID生成策略表)

columnName dataType length 是否主键 是否不为空 描述
ID int 10 y y 生成表的ID
PK_NAME varchar 50 n y 需要使用此策略的表名称
PK_VALUE int 10 n y 起始值,种子

·2. 插入几个值

ID PK_NAME PK_VALUE
1 CUSTOMER_ID 1
2 STUDENT_ID 10
3 ORDER_ID 100

·3. 编写Customer.java

private Integer id;

@TableGenerator(name="ID_GENERATOR",table="JPA_ID_GENERATOR",pkColumnName="PK_NAME",
    pkColumnValue="CUSTOMER_ID",valueColumnName="PK_VALUE",allocationSize=100)
@GeneratedValue(strategy=GenerationType.TABLE,generator="ID_GENERATOR")
@Id
public Integer getId(){
    return id;
}

·4.
执行向Customer表中插入2条数据(因为ID采用table生成策略,所以插入数据时,不需要指定ID)

插入后,结果显示Customer表的ID分别为
100
200

@Transient注解