话说:
生活中离不开吃喝玩乐,代码世界自然离不开CURD。到现在为止,我也觉得CURD蛮好的,很多东西不都是建立在基础之上的么。
目录
1.创建JPA工程
2.基本注解解释
3.实现CURD
4.总结
开发工具:Eclipse
难度系数:★★☆☆☆
建议用时:1H
1.创建JPA工程
Eclipse==》new Project ==>new JPA Project
==》添加Tomcat 和jre环境 ==》处理 At least one user library must be selected 这个问题!
这一句表明:JPA在Eclipse中是需要这些包包的。
从 https://www.eclipse.org/eclipselink/downloads/ 处下载 EclipseLink 2.5.2 Installer Zip (38 MB) 资源(也可以选择其它版本)。EclipseLink中提供了所有持久化服务的的实现。
● 持久化服务将会用到下面三个jar包:
①、eclipselink.jar
②、javax.persistence.source_2.1.0.v201304241213.jar
③、javax.persistence_2.1.0.v201304241213.jar
● 将下载好的EclipseLink 2.5.2压缩包解压到任何你想用于完成安装的文件夹中。我将文件解压到 “.\workspace\libraries\EclipseLink 2.5.2” 文件夹下。
创建完成后,项目初步结构是这样的:
2.基本注解解释
1. @Table 标注类对应的表
2. * 若表名和类型相同时,省略@Table,比如类Users 和表 users;
3. * 若不相同时,必须有@Table,并设置name,为该类对应的表名。@Table(name="users")
4. *
5. * @Entity 标注实体
6. *
7. * @Id 标注id
8. *
9. * @Transient 标注该属性不做与表的映射(原因:可能表中没有该属性对应的字段)
10. * 有该注解,在执行sql语句时,就不会出现该属性,否则会有,若表中没有该字段则会报错
11. *
12. * @Basic 默认所有属性都有该注解(主键需要单独使用@Id),所以可以省略
13. * 该注解可以放在属性上,也可以放在对应的getter方法上。
14. * 注意:要么统一将@Basic放在属性上,要么统一放在对应的getter方法上。(一般都放在属性上,可读性比较好)
15. *
16. * @Column 类中属性名和表中对应字段名不相同时,会使用该注解,指明在类中对应的字段
17. * @Column(name="对应的表中字段名")
@GeneratedValue:主键的产生策略,通过strategy属性指定。
主键产生策略通过GenerationType来指定。GenerationType是一个枚举,它定义了主键产生策略的类型。
1、AUTO自动选择一个最适合底层数据库的主键生成策略。如MySQL会自动对应auto increment。这个是默认选项,即如果只写@GeneratedValue,等价于@GeneratedValue
(strategy=GenerationType.AUTO)。
2、IDENTITY 表自增长字段,Oracle不支持这种方式。
3、SEQUENCE 通过序列产生主键,MySQL不支持这种方式。
4、TABLE 通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。不同的JPA实现商生成的表名是不同的,如 OpenJPA生成openjpa_sequence_table表,Hibernate生成一个hibernate_sequences表,而TopLink则生成sequence表。这些表都具有一个序列名和对应值两个字段,如SEQ_NAME和SEQ_COUNT。
3.实现CURD
1.项目结构
2.配置文件
3.代码
4.总结
整体参考这篇博客即可:
这篇有完整的包结构:
我的这个跟别人的博客有啥区别?
1)有明确的运行结果
2)代码最后有明确的处理异常过程。
1.项目结构
注意,按照图示包的内容,在src下新建一个folder,存放各种包包,然后build path即可。
2.配置文件
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="myjpa01" transaction-type="RESOURCE_LOCAL" >
<!-- 配置Jpa ORM 产品 -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider </provider>
<!-- 添加对应持久化的类 -->
<class>com.hmc.pojo.Users</class>
<properties>
<!-- jpa中连接数据库 -->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
<!-- jpa中配置hibernate的基本属性 -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
3.代码
1)pojo
2)test
3)util
1)pojo-Users
package com.hmc.pojo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
Author:meice Huang
Time:2018年4月4日下午12:37:21
*/
@Table(name="users")
@Entity
public class Users {
/**
* create database jpa;
* use jpa;
*
* create table users(
* userId int auto_increment primary key,
* userName varchar(50) not null,
* age int
*
* );
*
* #模拟数据
* insert into users (userName,age) values
* ("刘备",52),
* ("周瑜",35),
* ("诸葛亮",27);
*/
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="userId")
private Integer userId;
@Column(name="userName")
private String userName;
@Column(name="age")
private int age;
public Users() {}
public Users(Integer userId, String userName, int age) {
super();
this.userId = userId;
this.userName = userName;
this.age = age;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Users [userId=" + userId + ", userName=" + userName + ", age=" + age + "]";
}
}
2)test-Test_jpa
package com.hmc.test;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Persistence;
import javax.transaction.Transaction;
import org.junit.Test;
import com.hmc.pojo.Users;
import com.hmc.util.GetJpaManager;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TestGenerator;
/**
Author:meice Huang
Time:2018年4月4日下午2:07:09
*/
public class Test_jpa {
/**
* 查-1
*/
@Test
public void testFind() {
//1.获取factory
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myjpa01");
//2.获取Manager
EntityManager em = factory.createEntityManager();
//3.获取事务,并开启事务
EntityTransaction transaction =em.getTransaction();
transaction.begin();
Users users = em.find(Users.class, 1);
System.out.println(users.getUserName());
//4.提交事务
transaction.commit();
em.close();
factory.close();
}
/**
* 运行结果:
* 四月 04, 2018 4:39:54 下午 org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate:
select
users0_.userId as userId1_0_0_,
users0_.age as age2_0_0_,
users0_.userName as userName3_0_0_
from
users users0_
where
users0_.userId=?
1111
四月 04, 2018 4:39:56 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:mysql://localhost:3306/jpa]
*/
/**
* 查-2 find()和getReference()的区别类似Hibernate的的get()和load() 懒加载
*/
@Test
public void testGet() {
//这里利用自己封装好的GetJpaManager这个Utils
EntityManager em = (EntityManager)GetJpaManager.getJpaMap().get("EntityManager");
EntityTransaction transaction = (EntityTransaction)GetJpaManager.getJpaMap().get("EntityTransaction");
//transaction.begin();
//采用 懒加载方式执行查询
Users users = em.getReference(Users.class, 2);
System.out.println("懒加载查出的对象是: "+users);
//transaction.commit();
em.close();
}
/**
* 运行结果:
* 四月 04, 2018 10:27:37 下午 org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate:
select
users0_.userId as userId1_0_0_,
users0_.age as age2_0_0_,
users0_.userName as userName3_0_0_
from
users users0_
where
users0_.userId=?
懒加载查出的对象是: Users [userId=2, userName=2222, age=57]
*
* 不开启事务,照样可以查询。疑问:find()和getReference()2种方法查询区别和Hibernate的区别真的一样么?
*/
/**
* 增
*/
@Test
public void testAdd() {
//1.获取Factory
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myjpa01");
//2.获取Manager
EntityManager em = factory.createEntityManager();
//3.获取事务,并开启事务
EntityTransaction transaction = em.getTransaction();
transaction.begin();
//4.执行SQL
Users users = new Users();
users.setUserName("刘备");
users.setAge(56);
em.persist(users);
//5.提交事务 ,关闭资源
transaction.commit();
em.close();
factory.close();
}
/**
* 运行结果:
* INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate:
insert
into
users
(age, userName)
values
(?, ?)
四月 04, 2018 5:18:50 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:mysql://localhost:3306/jpa]
*/
/**
* 增 -增的同时加载配置信息
* 初始化一个实体工厂有2种方式
*/
@Test
public void testAdd2() {
//1.获取factory
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.format_sql", "false");
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myjpa01", properties);
//2.获取manager
EntityManager em = factory.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
//3.执行新增
Users users = new Users();
users.setUserName("八戒");
users.setAge(32);
em.persist(users);
//4.提交事务并关闭资源
transaction.commit();
em.close();
factory.close();
}
/**
* 运行结果:
*
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate: insert into users (age, userName) values (?, ?)
四月 04, 2018 5:37:19 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008
*/
/**
* 改
*/
@Test
public void testUpdate() {
//不能通过封装的来执行改、删,因为是同一个事务
//EntityManager em =(EntityManager) GetJpaManager.getJpaMap().get("EntityManager");
//EntityTransaction transaction =(EntityTransaction) GetJpaManager.getJpaMap().get("EntityTransaction");
EntityManager em = Persistence.createEntityManagerFactory("myjpa01").createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
//先查到想要修改的数据
Users users = em.find(Users.class, 4);
users.setUserName("八戒,好吃佬");
transaction.commit();
//关闭资源
em.close();
}
/**
* 运行结果:
四月 05, 2018 11:39:37 下午 org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate:
select
users0_.userId as userId1_0_0_,
users0_.age as age2_0_0_,
users0_.userName as userName3_0_0_
from
users users0_
where
users0_.userId=?
Hibernate:
update
users
set
age=?,
userName=?
where
userId=?
*/
/**
* 删
*/
@Test
public void testDel() {
EntityManager em =Persistence.createEntityManagerFactory("myjpa01").createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Users users = em.find(Users.class, 3);
em.remove(users);
transaction.commit();
em.close();
}
/**
* 运行结果:
* 四月 05, 2018 11:31:04 下午 org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate:
select
users0_.userId as userId1_0_0_,
users0_.age as age2_0_0_,
users0_.userName as userName3_0_0_
from
users users0_
where
users0_.userId=?
Hibernate:
delete
from
users
where
userId=?
*/
/**
* 类型1:缺包
*
* 1.Caused by: java.lang.ClassNotFoundException: org.jboss.logging.Logger
* 缺jboss包,下载即可。
*
* 2.Caused by: java.lang.ClassNotFoundException: javax.transaction.SystemException
* 缺少了一个jta-1.1.0.jar包,加进去就可以了! 去Maven仓库搜索jta下载。
*
* 3.Caused by: java.lang.ClassNotFoundException: org.dom4j.io.STAXEventReader
* 缺少dom4j包
*
* 4.Caused by: java.lang.ClassNotFoundException: org.hibernate.annotations.common.reflection.ClassLoaderDelegate
* 有时候你包虽然有,但是是N多年前的包了,要下载最近年限的,因为有变化。
*
* 5.ava.lang.NoSuchMethodError: org.hibernate.annotations.common.reflection.java.JavaReflectionManager.setMetadataProvider(Lorg/hibernate/annotations/common/reflection/MetadataProvider;)V
* 如果已经有这个包,jar包冲突导致。笔者就是下载了多个hibernate.annotations.common导致的。根据报错信息得知,没有setMetadataProvider()方法
*
* 类型2:驱动加载
*
* 6. ... 37 more
Caused by: java.lang.ClassNotFoundException: Could not load requested class : com.mysql.jdbc.driver
加载驱动失败!很明显,这个驱动类全名写错了!好像是6.0版本之后:com.mysql.cj.jdbc.Driver
7.
java.lang.IllegalArgumentException: Provided id of the wrong type for class com.hmc.pojo.Users. Expected: class java.lang.Integer
Caused by: org.hibernate.TypeMismatchException: Provided id of the wrong type for class com.hmc.pojo.Users. Expected: class java.lang.Integer, got class java.lang.String
这里很明显:数据库userId和实体类类型不一致,查看下,笔者都是int类型,没问题!
那么就是Users users = em.find(Users.class, 1); 这个地方,第一次写成了"1",你要找的东西类型要和设计一致!
*/
/**
* 1、如果事务没有提交,报错:
* at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: org.hibernate.exception.SQLGrammarException: error performing isolated work 隔离性错误!
2、java.sql.SQLSyntaxErrorException: Table 'jpa.hibernate_sequence' doesn't exist
Caused by: java.sql.SQLSyntaxErrorException: Table 'jpa.hibernate_sequence' doesn't exist
这里_sequence应该能想到是主键生成策略的问题,所以在注解那一块找。主键生成策略有:AUTO \ IDENTITY \SEQUENCE \TABLE
@GeneratedValue(strategy=GenerationType.IDENTITY)
3.Caused by: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.hmc.pojo.Users
这里表达:主键生成策略,要手动配置,不能自动生成。@GeneratedValue这样就是默认的,等同于GenerationType.AUTO。不行,需要手动指定为Identity
4.java.sql.SQLException: Incorrect string value: '\xE4\xB8\x8D\xE4\xB8\x89...' for column 'userName' at row 1
这个报错背景:我重置了MySQL的编码,之前默认是latin,发现乱码之后,在/etc下新增my.cnf配置,然后重启。
由于数据库编码已经修改,但是已经建好的jpa数据库和表默认编码还是latin,所以报这个错。
搞定方法:删掉数据库和表,重建。搞定!
*/
}
3)util-GetJpaManager
package com.hmc.util;
/**
Author:meice Huang
Time:2018年4月4日下午5:44:18
*/
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import org.junit.Test;
public class GetJpaManager {
/**
* 这么封装仍然不够简洁
* 事务还是要单独写
* @return
*/
@Test
public static EntityManager getEntityManager() {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myjpa01");
EntityManager em = factory.createEntityManager();
return em;
}
/**
* 这个方法可以返回2个值:
* EntiryManager
* EntiryTransaction
* @return
*/
@Test
public static Map<String, Object> getJpaMap() {
Map<String, Object> jpaMap = new HashMap<>();
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myjpa01");
EntityManager em = factory.createEntityManager();
EntityTransaction transaction = em.getTransaction();
jpaMap.put("EntityManager", em);
jpaMap.put("EntityTransaction", transaction);
return jpaMap;
//问题在于如何关闭?factory
}
}
4.总结
1.可以直接新建jpa工程,jpa是什么?是一个架构规范。有点类似JDBC.Hibernate是这个规范的一个典型实现。
2.JPA的API:
CURD: 查:find(Users.class,2) 增:persist(对象); 改:find()之后修改属性; 删:remove(对象)
3.在研究查的2种方式:find()和getReference()的区别?为什么要设置这种区别?这和Hibernate的get()和load()方法有异曲同工之处?
4.remove()的时候,只能删除持久化对象,不能移除游离对象,这句话如何理解?
好了,下期再会!
感情有时候也像这篇博客一样“难产“,看似那么自然的事情,为什么就如此。。。。。。