JPA案例
搭建环境
创建maven工程,导入坐标
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--hibernate对jpa的支持包-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.0.7.Final</version>
</dependency>
<!--c3p0-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.0.7.Final</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
</dependencies>
配置jpa的配置文件
- 位置:配置到类路径下META-INF的文件夹下
- 命名:persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<!--
需要配置persistence-unit节点
持久化单元:
name:持久化单元名称
transaction-type:事务管理的方式
JTA:分布式事务管理
RESOURCE_LOCAL:本地事务管理
-->
<persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
<!--jpa的实现方式-->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!--
数据库信息
用户名:javax.persistence.jdbc.user
密码: javax.persistence.jdbc.password
驱动: javax.persistence.jdbc.driver
url: javax.persistence.jdbc.url
-->
<properties>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///dev?serverTimezone=UTC"/>
<!--
可选配置:配置实现jpa实现方(hibernate)的配置信息
显示sql :true|false
自动创建数据库表 :hibernate.hbm2ddl.auto
create :程序运行时创建数据库表(如果有表,先创建表再创建)
update :程序运行时创建表(如果有表不会创建表)
none :不会创建表
-->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
</persistence>
编写客户的实体类 配置实体类和表,类中属性和表中字段的映射关系
/**
* 客户的实体类
* @Entity 声明实体类
* @Table 配置实体类和表的映射关系
* name:配置数据库表的名称
*/
@Entity
@Table(name = "cst_customer")
public class Customer {
/**
* @Id 声明主键的配置
* @GeneratedValue 配置主键的生成策略
* GenerationType.IDENTITY :自增(mysql)
* 底层数据库必须支持自动增长
* GenerationType.SEQUENCE :序列(oracle)
* 底层数据库必须支持序列
* GenerationType.TABLE :jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增
* GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略
* @Column 配置属性和字段的映射关系
* name:数据库表中字段的名称
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cust_id")
private Long custId;//客户主键
@Column(name = "cust_name")
private String custName;//客户名称
@Column(name = "cust_source")
private String custSource;//客户来源
@Column(name = "cust_lever")
private String custLever;//客户级别
@Column(name = "cust_industry")
private String custIndustry;//客户所属行业
@Column(name = "cust_phone")
private String custPhone;//客户联系方式
@Column(name = "cust_address")
private String custAddress;//客户地址
@Override
public String toString() {
return "Customer{" +
"custId=" + custId +
", custName='" + custName + '\'' +
", custSource='" + custSource + '\'' +
", custLever='" + custLever + '\'' +
", custIndustry='" + custIndustry + '\'' +
", custPhone='" + custPhone + '\'' +
", custAddress='" + custAddress + '\'' +
'}';
}
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustLever() {
return custLever;
}
public void setCustLever(String custLever) {
this.custLever = custLever;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
}
测试保存客户到数据库中
@Test
public void testInsert(){
//1.加载配置文件,创建实体类管理器工厂
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
//2.通过实体管理器工厂获取实体管理器
EntityManager entityManager = entityManagerFactory.createEntityManager();
//3.获取事务管理器
EntityTransaction transaction = entityManager.getTransaction();
//4.开启事务
transaction.begin();
Customer customer = new Customer();
customer.setCustName("xiaojiang");
customer.setCustAddress("luoyangshi");
//5.保存
entityManager.persist(customer);
//6.提交事务
transaction.commit();
//7.释放资源
entityManager.close();
entityManagerFactory.close();
}
解决 java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException**
原因:jdk版本过高,9以上就会报错
解决方法:maven中加入依赖
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
jpa操作步骤
-
1)、加载配置文件创建实体类管理工厂
Persistence:静态方法createEntityManagerFactory(“myJpa”)(根据持久化单元名称创建实体类管理工厂)
作用:创建实体类管理工厂 -
2)、根据实体类管理工厂创建实体类管理器
EntityManagerFactory:获取EntityManager对象
方法createEntityManager()- 内部维护了很多的内容
数据库信息
缓存信息
所有的实体管理器对象
在创建EntityManagerFactory的过程中会根据配置创建数据库表
- 内部维护了很多的内容
-
EntityManagerFactory创建过程比较浪费资源
特点:线程安全的对象
如何解决EntityManagerFactory的创建过程浪费资源的问题- 静态代码块形式创建一个公共的EntityManagerFactory对象
public class JpaUtil { private static EntityManagerFactory entityManagerFactory; static { entityManagerFactory = Persistence.createEntityManagerFactory("myJpa"); } public static EntityManager getEntityManager(){ return entityManagerFactory.createEntityManager(); } }
-
3)、创建事务对象
EntityManager对象:实体类管理器- getTransaction():创建事务对象
- persist():保存
- merge():更新
- remove():删除
- find/getRefrence() :根据id查询
Transaction对象:事务
- begin(): 开启事务
- conmmit():提交事务
- rollback():回滚事务
-
4)、增删改查操作
-
5)、提交事务/回滚事务
-
6)、释放资源
/**
* 查询的对象就是当前实体类对象
* 在调用方法的时候就发送sql语句查询数据库
*/
@Test
public void testFind(){
EntityManager entityManager = JpaUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Customer customer = entityManager.find(Customer.class, 1l);
transaction.commit();
System.out.println(customer);
entityManager.close();
}
/**
* 获取的对象是个动态代理对象
* 调用getReference方法不会立即发送sql语句查询数据库,当调用查询结果对象的时候才会发送查询的sql语句
* 延迟加载(懒加载)
*/
@Test
public void testReference(){
EntityManager entityManager = JpaUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Customer customer = entityManager.getReference(Customer.class, 1l);
transaction.commit();
System.out.println(customer);
entityManager.close();
}
@Test
public void testMerge(){
EntityManager entityManager = JpaUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Customer customer = entityManager.getReference(Customer.class, 1l);
customer.setCustAddress("jianxiqu");
entityManager.merge(customer);
transaction.commit();
entityManager.close();
}
@Test
public void testRemove(){
EntityManager entityManager = JpaUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Customer customer = entityManager.getReference(Customer.class, 1l);
entityManager.remove(customer);
transaction.commit();
entityManager.close();
}
SpringDataJpa案例
搭建环境
导入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.7.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.0.7.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.10.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.5</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.5</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
编写配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc
https://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!--创建entityManagerFactory对象-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--实体类所在包-->
<property name="packagesToScan" value="ganxie.xiaowen.jpa.bean"/>
<!--jpa的实现厂家-->
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
</property>
<!--jpa的供应商适配器-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!--指定数据库类型-->
<property name="database" value="MYSQL"/>
<!--数据库支持的特有语法-->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
<!--是否自动创建数据库表 -->
<property name="generateDdl" value="false"/>
<!--是否显示sql语句-->
<property name="showSql" value="true"/>
</bean>
</property>
<!--jpa的高级特性-->
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"/>
<property name="password" value="1234"/>
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///dev?serverTimezone=UTC"/>
</bean>
<!--整合spring data Jpa-->
<jpa:repositories base-package="ganxie.xiaowen.jpa.dao" entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager"/>
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--包扫描-->
<context:component-scan base-package="ganxie.xiaowen.jpa"/>
<!--声明式事务-->
</beans>
编写实体类并将实体类和表,属性和字段一一对应
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "address")
private String address;
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
编写dao接口
/**
* 符合springDataJpa的dao层接口,
* 只需要继承两个接口JpaRepository,JpaSpecificationExecutor并提供相应的泛型
* JpaRepository<封装的实体类,主键数据类型> 封装了基本CRUD操作
* JpaSpecificationExecutor<封装的实体类> 封装了复杂查询
*/
public interface UserDao extends JpaRepository<User,Integer>, JpaSpecificationExecutor<User> {
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestUserDao {
@Autowired
private UserDao userDao;
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testFindOne() {
User user = userDao.findOne(1);
System.out.println(user);
}
/**
* 更新保存都是save()方法,如果传入的主键存在,就根据主键查找并修改
* 如果传入的主键不存在,就执行保存操作。
*/
@Test
public void testInsert() {
User user = new User();
user.setName("test");
user.setAddress("alibaba");
userDao.save(user);
}
@Test
public void testUpdate() {
User user = new User();
user.setId(4);
user.setName("test");
user.setAddress("fushan");
userDao.save(user);
}
@Test
public void testDelete() {
userDao.delete(4);
}
}
原理
- 通过JdkDynamicAopProxy的invoke方法创建一个动态代理对象
- SimpleJpaRepository当中封装了JPA的操作(借助JPA的api完成数据库的CRUD)
- 通过hibernate完成数据库操作(封装了jdbc)
Specification
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestSpecification {
@Autowired
private UserDao userDao;
/**
* 测试查询
*/
@Test
public void testFind() {
Specification<User> specification = new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Path<Object> id = root.get("id");
Predicate equal = cb.equal(id, 1);
return equal;
}
};
User user = userDao.findOne(specification);
System.out.println(user);
}
/**
* 测试多条件查询
*/
@Test
public void testComplex() {
Specification<User> specification = new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Path<Object> name = root.get("name");
Path<Object> address = root.get("address");
Predicate equal = cb.equal(name, "小兰");
Predicate equal1 = cb.equal(address, "洛阳市");
Predicate predicate = cb.and(equal, equal1);
return predicate;
}
};
User user = userDao.findOne(specification);
System.out.println(user);
}
/**
* 测试模糊查询并排序
*/
@Test
public void testLikeAndSort() {
Specification<User> specification = new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Path<Object> name = root.get("name");
Predicate predicate = cb.like(name.as(String.class), "小%");
return predicate;
}
};
Sort sort = new Sort(Sort.Direction.DESC,"id");
List<User> users = userDao.findAll(specification,sort);
for (User user : users) {
System.out.println(user);
}
}
/**
* 测试分页查询
*/
@Test
public void testPage() {
/**
* PageRequest 是Pageable接口的实现类
* 第一个参数:当前查询的页数(从0开始)
* 第二个参数:每页查询的数量
*/
PageRequest pageRequest = new PageRequest(0,2);
Page<User> users = userDao.findAll(pageRequest);
for (User user : users) {
System.out.println(user);
}
}
}