Spring Data:统一和简化对不同类型持久性存储(关系数据库系统和NoSQL数据存储)的访问。
特性:模板制作、对象/数据存储映射、Repository支持
相同:
1.都跟数据库操作有关,JPA是JDBC的升华。
2.JPA和JDBC都是一组规范接口
不同之处:
1.JDBC是由各个关系型数据库实现的,JPA是由ORM框架实现。
2.JDBC使用SQL语句和数据库通信,JPA用面向对象方式,通过ORM框架来生成SQL,进行操作。
3.JPA在JDBC之上,JPA也要依赖JDBC才能操作数据库。
/**
* 客户的实体类
* 配置映射关系
* 1.实体类和表的映射关系
* @Entity:声明实体类
* @Table:配置实体类和表的映射关系
* name : 配置数据库表的名称
* 2.实体类中属性和表中字段的映射关系
*/
@Data
@Entity
@Table(name = "tb_customer")
public class Customer {
/**
* @Id:声明主键的配置
* @GeneratedValue:配置主键的生成策略
* strategy:
* GenerationType.IDENTITY :自增,mysql
* 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增)
* GenerationType.SEQUENCE : 序列,oracle
* 底层数据库必须支持序列
* GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增
* GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略
* @Column:配置属性和字段的映射关系
* name:数据库表中字段的名称
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "customer_id")
private Long Id; //客户的主键
@Column(name = "customer_name")
private String name;//客户名称
@Column(name="customer_age")
private int age;//客户年龄
@Column(name="customer_sex")
private boolean sex;//客户性别
@Column(name="customer_phone")
private String phone;//客户的联系方式
@Column(name="customer_address")
private String address;//客户地址
}
@Entity 作为hiberbate实体类
@Tabel(name=“表名”) 映射的表名
@Id 声明主键
@GenerateValue 主键的生成策略
@Column(name=“字段名”) 表单的列名
DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driverproperty>
<property name="connection.url">jdbc:mysql://localhost:3306/bianchengbang_jdbc?characterEncoding=UTF-8property>
<property name="hibernate.connection.username">rootproperty>
<property name="hibernate.connection.password">rootproperty>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialectproperty>
<property name="hibernate.show_sql">trueproperty>
<property name="hibernate.format_sql">trueproperty>
<property name="hbm2ddl.auto">updateproperty>
<mapping resource="net/biancheng/www/mapping/User.hbm.xml"/>
<mapping class="com.test.pojo.Customer"/>
session-factory>
hibernate-configuration>
依赖不用改,多加一个配置文件。IDEA有persistence模板:setting=》file and code Template=》JPA==》Deployment descriptors=》persistenceXX.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProviderprovider>
<properties>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.url" value="jdbc:mysql://127.0.0.1:3306/hibernate_jpa?characterEncoding=UTF-8"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="password"/>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update" />
properties>
persistence-unit>
persistence>
/**
* 测试jpa的保存 案例:保存一个客户到数据库中
* Jpa的操作步骤
* 1.加载配置文件创建工厂(实体管理器工厂)对象
* 2.通过实体管理器工厂获取实体管理器
* 3.获取事务对象,开启事务
* 4.完成增删改查操作
* 5.提交事务(回滚事务)
* 6.释放资源
*/
@Test
public void testSave() {
//1.加载配置文件创建工厂(实体管理器工厂)对象
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
//2.通过实体管理器工厂获取实体管理器
EntityManager em = factory.createEntityManager();
//3.获取事务对象,开启事务
EntityTransaction tx = em.getTransaction();
tx.begin();
//4.完成增删改查操作:保存一个客户到数据库中
Customer customer = new Customer();
customer.setName("Sam");
customer.setAddress("Beijing");
//保存操作
em.persist(customer);
//5.提交事务
tx.commit();
//6.释放资源
em.close();
factory.close();
}
---------------------------------api
//立即查询
Customer customer = em.find(Custormer.class,1L);
//懒查询
Customer customer = em.getReference(Custormer.class,1L);
//更新 指定id会先查询数据是否有变化,有变化则更新,不指定id会插入一条数据
Customer customer = new Customer();
customer.setCustId(5L);
customer.setCustName("dfg");
em.merge(customer);
//更新 -- JPQL 不会进行查询 使用实体类名和属性名
String jpql = "Update Customer set name=:name where id=:id ";
em.createQuery(jpql).setParameter("name","李四").setParameter("id","5L").executeUpdate();
//更新 -- 使用SQL 使用表名和字段名
String sql = "Update tb_customer set name=:name where id=:id ";
em.createNativeQuery(sql).setParameter("name","李四11").setParameter("id","5L").executeUpdate();
//删除 先查再删除
//不能删除游离数据,只能删除持久化数据(从数据库里查出来的数据)
Customer customer = em.find(Custormer.class,5L);
em.remove(customer);
刚创建出来的对象,它此时还没与entityManager发生关系,没有被持久化,不处于entityManager中的对象。
与entityManager发生关系,已经被持久化,是数据库实在的记录,比如执行了persist()、find()、merge()。
情况:
持久状态进行了修改会同步数据库;把数据库里的记录查询出来做修改并没有执行保存操作,也会把更新数据的操作同步到数据库。
执行remove()方法,事物提交之前。
游离状态是提交到数据库后,事务commit后实体的状态。比如该对象commit之后在数据库有对应的数据,但是它还没与entityManager发生关系。此时实体的属性可以做任何改变,也不会同步到数据库,因为事务已经提交了。
persist方法可以将实例转换为managed(托管)状态,在调用flush()方法或提交事物之后 ,实例将会被插入
到数据库中。
对不同状态下的实例A,persist会产生以下操作:
1)如果A是一个new状态的实体,它将会转为managed状态;
2)如果A是一个managed状态的实体,它的状态不会发生任何改变,但是系统仍会在数据库执行 insert 操作;
3)如果A是一个removed(删除)状态的实体,它将会转换为受控状态;
4)如果A是一个detached(分离)状态的实体,该方法会抛出IllegalArgumentException异常,具体异常根据不同的JPA实现有关。
merge方法的主要作用是将用户对一个detached状态实体的修改
进行归档,归档后将产生一个新的managed状态对象。
对不同状态下的实例A,merge会产生以下操作:
1)如果A是一个detached状态的实体,该方法会将A的修改提交到数据库,并返回一个新的managed状态的实例A2;
2)如果A是一个new状态的实体,该方法会产生一个根据A产生的managed状态实体A2;
3)如果A是一个managed状态的实体,它的状态不会发生任何改变,但是系统仍会在数据库执行update操作。
4)如果A是一个removed状态的实体,该方法会抛出IllegalArgumentException异常。
refresh方法可以保证当前的实例与数据库中的实例内容一致。
对不同状态下的实例A,refresh会产生以下操作:
1)如果A是一个new状态的实体,A的状态不会发生任何改变,但系统仍会在数据库中执行delete语句;
2)如果A是一个managed状态的实体,它的属性将会和数据库中的数据同步;
3)如果A是一个removed状态的实体,该方法将会抛出异常:Entity not managed
4)如果A是一个detached状态的实体,该方法将会抛出异常;
remove方法可以将实体转换为removed状态,并且在调用flush()方法或提交事物后删除数据库中的数据。
对不同状态下的实例A,remove会产生以下操作:
1)如果A是一个new状态的实体,A的状态不会发生任何改变,但系统仍会在数据库中执行delete语句;
2)如果A是一个managed状态的实体,它的状态会转换为removed;
3)如果A是一个removed状态的实体,不会发生任何操作;
4)如果A是一个detached状态的实体,该方法将会抛出异常;
父项目
添加spring data的统一版本管理,它可以统一子项目的Spring Data JDBC、Spring Data JPA 、Spring Data Redis等版本。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-bomartifactId>
<version>2022.0.2version>
<scope>importscope>
<type>pomtype>
dependency>
dependencies>
dependencyManagement>
子项目
spring 项目需要另外添加hibernate依赖,spring boot项目不需要。
<dependencies>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-jpaartifactId>
dependency>
<dependencies>
整合jpa
< jpa:repositories />对应@EnableJpaRepositories注解
定义接口继承CrudRepository接口
public interface CrudRepository<T, ID> extends Repository<T, ID> {}
查询
插入
更新 先查再更新
删除 先查再删除,把new出来的实例的游离状态改为持久状态
//标记当前类为配置类
@Configuration
//启动jpa 相当于xml的 标签 basePackage:指定数据返回层.接口
@EnableJpaRepositories(basePackage="com.test.repositories")
//开启事务
@EnableTransactionManagement
class ApplicationConfig {
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUserName("root");
dataSource.setPassWord("123456");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/hibernate_jpa?characterEncoding=UTF-8");
return dataSource;
//使用内嵌内存数据库
/**
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
**/
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
//指定实体类的包
factory.setPackagesToScan("com.acme.domain");
factory.setDataSource(dataSource());
return factory;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
JPQL定义,参数可以使用索引指定,或参数名结合@Param注解指定。
用 法
增删改需要开启事务,@Transactional通常放在业务逻辑层上声明。
JPQL是不支持新增的,用Hibernate实现伪插入,只能插入从别的地方查到的值。
SQL
根据提供的主题关键字
(前缀)决定方法作用,谓词关键字
和修饰符决定查询条件。只支持查询和删除。官网使用说明,有详细使用方法的
例:
findBy(关键字)+ 属性名称(首字母大写)+ 查询条件(首字母大写)
只支持查询,只支持字符串(开头、包含、结尾、正则匹配)
,不支持嵌套或分组的属性约束。官网使用说明
实现:
//继承QueryByExampleExecutor接口
public interface CustomerRepository extends PagingAndSortingRepository<Customer, Long> ,QueryByExampleExecutor<Customer>{ … }
测试:
通过customer对象来进行筛选。
通过匹配器进行条件的限制。
对所有类型支持。
步骤:
1、通过root拿到需要设置条件的字段
2、通过CriteraBuilder设置不同类型条件
3、组合条件
实现:
//继承JpaSpecificationExecutor接口
public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
…
}
通用查询框架,借助QueryDSL可以在任何支持的ORM框架或SQL平台上以通用API方式构建查询。官网使用说明
实现:
//继承QuerydslPredicateExecutor
interface UserRepository extends CrudRepository<User, Long>, QuerydslPredicateExecutor<User> {
}
//官方例子,能直接实体类user.firstname是添加了插件
Predicate predicate = user.firstname.equalsIgnoreCase("dave")
.and(user.lastname.startsWithIgnoreCase("mathews"));
userRepository.findAll(predicate);