SpringDataJpa知识详解及使用

SpringDataJpa

自己整理,如有错误,请联系QQ:940416023进行修改

1.ORM思想

将对象与数据库表建立一种映射关系,这样就可以通过操作对象的方式实现对数据库表的操作

1.1 映射关系

Java类==表
类的属性==表的字段
类的对象==表的数据行

2. JPA与Hibernate介绍

JPA是SUN针对ORM映射的标准和规范
Hibernate是ORM的一种实现框架
使用JPA的特点
    1. 面向接口编程,标准化开发
    2. 配置简单,易用
    3. 提供了面向对象的查询语言,类似于SQL语法,易于查询

3.编写核心配置文件

3.1文件位置

META-INF/persistence.xml

3.2文件内容

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
     <!--transaction-type:RESOURCE_LOCAL 本地事务; JTA:分布式事务 -->
    <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
        <!--jpa的实现方式 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="root"/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>
            <!--是否打印SQL-->
            <property name="hibernate.show_sql" value="true" />
            <!--是否格式化SQL-->
            <property name="hibernate.format_sql" value="true" />
            <!--DDL语句设置-->
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <!--
				hbm2ddl取值:
						create: 程序运行时创建数据库表(如果有表,先删除表再创建)
                        update:程序运行时创建表(如果有表,不会创建表)
                        none:不会创建表
			-->
        </properties>
    </persistence-unit>
</persistence>

3.3主键生成策略(GeneratedValue)

SEQUENCE:序列(Oracle数据库用)
IDENTITY:数据库自增(Mysql数据库用)
TABLE:Hibernate负责生成主键值,并自动创建一个序列表,存储实体类对应表中的主键值.
AUTO:Hibernate自动选择主键生成策略(优先选择使用SEQUENCE)

4.JPA常用API介绍

4.1 Persistence

加载配置文件,创建EntityManagerFactory对象

4.2 EntityManagerFactory

创建EntityManager对象,并且是线程安全对象,全局共享一个即可

4.3 EntityManager

CURD操作的核心对象

getTransaction : 获取事务对象
persist : 保存操作
merge : 更新操作
remove : 删除操作
find/getReference : 根据id查询

4.4 EntityTransaction

操作事务的对象

begin:开启事务
commit:提交事务
rollback:回滚事务

5.JPA增删改查

5.1JPA工具类

/**
 * JPA工具类,用来获得EntityManager对象
 */
public class JpaUtils {
    private static EntityManagerFactory factory;
    static  {
        factory = Persistence.createEntityManagerFactory("myJpa");
    }
    public static EntityManager getEntityManager() {
       return factory.createEntityManager();
    }
}

5.2根据ID查询

find和getReference的的异同

  • 相同点
    都可以根据ID查询对象数据
  • 不同点
    find方法立即加载,getReference懒加载
    find方法返回实体类对象,getReference返回代理对象
    如果未查询到数据,find方法返回null,getReference会报错.
    

5.3根据ID删除对象

remove

5.4根据ID更新对象

merge

6. SpringDataJPA概述

SpringDataJPA是Spring针对JPA进行封装的框架,目的是简化JPA针对DB持久层的操作

6.1配置文件

applicationContext.xml

<!-- 1.创建entityManagerFactory对象交给spring容器管理-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <!--配置的扫描的包(实体类所在的包) -->
    <property name="packagesToScan" value="cn.itcast.domain" />
    <!-- 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="generateDdl" value="true" />
            <!--指定数据库类型 -->
            <property name="database" value="MYSQL" />
            <!--数据库方言:支持的不同数据库sql特有语法 -->
            <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
            <!--是否显示sql -->
            <property name="showSql" value="true" />
        </bean>
    </property>
    <!--jpa的方言 :JPA实现厂商高级的特性 -->
    <property name="jpaDialect" >
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
</bean>
<!--2.创建数据库连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="user" value="root"></property>
    <property name="password" value="root"></property>
    <property name="jdbcUrl" value="jdbc:mysql:///jpa" ></property>
    <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
</bean>
<!--3.整合spring dataJpa-->
<jpa:repositories base-package="cn.itcast.dao" entity-manager-factory-ref="entityManagerFactoty" />
<!--4.配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactoty"></property>
</bean>
<!-- 5. 配置包扫描-->
<context:component-scan base-package="cn.corn"/>

6.2增删改查

增:save
删:delete
改:save
查:findOne
	getOne:需要Transactional
查询所有:findAll
判断某条数据是否存在:exists
统计查询:count
NO.关键词实例同功能JPQL
1AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
2OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
3Is,EqualsfindByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
4BetweenfindByStartDateBetween
5LessThanfindByAgeLessThan… where x.age < ?1
6LessThanEqualfindByAgeLessThanEqual… where x.age ⇐ ?1
7GreaterThanfindByAgeGreaterThan… where x.age > ?1
8GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
9AfterfindByStartDateAfter… where x.startDate > ?1
10BeforefindByStartDateBefore… where x.startDate < ?1
11IsNullfindByAgeIsNull… where x.age is null
12IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
13LikefindByFirstnameLike… where x.firstname like ?1
14NotLikefindByFirstnameNotLike… where x.firstname not like ?1
15StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)
16EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)
17ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)
18OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
19NotfindByLastnameNot… where x.lastname <> ?1
20InfindByAgeIn(Collection ages)… where x.age in ?1
21NotInfindByAgeNotIn(Collection age)… where x.age not in ?1
22TRUEfindByActiveTrue()… where x.active = true
23FALSEfindByActiveFalse()… where x.active = false
24IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)

7.Specification动态条件查询

7.1 实现步骤

1. Dao接口继承JpaSpecificationExecutor
2. 创建Specification对象封装查询条件
3. 调用JpaSpecificationExecutor接口方法,传递Specification对象进行条件查询

7.2案例

7.2.1 单条件查询
@Test
public void testSpec() {
  Specification<Customer> spec = new Specification<Customer>() {
     public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
     		//1.获得条件查询属性
     		Path<Object> custName = root.get("custName");
     		//2.构造查询条件;   
         	//同功能JPQL: from Customer where  custName = "参数"
     		Predicate predicate = cb.equal(custName, "参数");
            return predicate;
      }
  };
  Customer customer = customerDao.findOne(spec);
  System.out.println(customer);
}
7.2.2 多条件
@Test
public void testSpec1() {
  Specification<Customer> spec = new Specification<Customer>() {
     public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        //属性1:客户名
        Path<Object> custName = root.get("custName");
        //属性2:所属行业
        Path<Object> custIndustry = root.get("custIndustry");
        //构造查询条件
        //1.构造客户名的精准匹配查询
        Predicate p1 = cb.equal(custName, "传参数");
        //2.构造所属行业的精准匹配查询
        Predicate p2 = cb.equal(custIndustry, "参数");
        //3.将多个查询条件进行组合
        //同功能JPQL语句:from Customer where custName = "参数" and custIndustry="参数"
        Predicate and = cb.and(p1, p2);
        return and;
     }
  };
  Customer customer = customerDao.findOne(spec);
}
7.2.3 带条件查询并排序
@Test
public void testSpec3() {
  Specification<Customer> spec = new Specification<Customer>() {
     public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            //查询属性:客户名
            Path<Object> custName = root.get("custName");
            //查询方式:模糊匹配,除过equals的其他查询方式必须指定比较的属性类型
            Predicate like = cb.like(custName.as(String.class), "参数%");
            return like;
        }
    };
    //创建排序对象
    Sort sort = new Sort(Sort.Direction.DESC,"custId");
    //执行查询
    List<Customer> list = customerDao.findAll(spec, sort);
    for (Customer customer : list) {
        System.out.println(customer);
    }
}
7.2.4 带条件分页查询
@Test
public void testSpec4() {
    //条件条件对象
    Specification spec = new Specification() {
        public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
            //查询属性:客户名
            Path<Object> custName = root.get("custName");
            //查询方式:模糊匹配,除过equals的其他查询方式必须指定比较的属性类型
            Predicate like = cb.like(custName.as(String.class), "参数%");
            return like;
        }
    };
    //创建分页对象,参数1:从哪里开始查;参数2:查询多少条
    Pageable pageable = new PageRequest(0,5);
    //分页查询
    Page<Customer> page = customerDao.findAll(spec, pageable);
}
7.2.5 动态查询
public void test(){
        Customer customer = new Customer();
        customer.setCustName("参数");
        Specification<Customer> spec = new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root,CriteriaQuery<?> query, CriteriaBuilder cb){
                List<Predicate> list = new ArrayList<Predicate>();
                //判断cusName是否有值
                if(customer.getCustName()!=null && !"".equals(customer.getCustName())){
                    Path<Object> cusName = root.get("custName");
                    Predicate p1 = cb.like(cusName.as(String.class), customer.getCustName());
                    list.add(p1);
                }
                //判断custIndustry是否有值
                if(customer.getCustIndustry()!=null && !"".equals(customer.getCustIndustry())){
                    Path<Object> custIndustry = root.get("custIndustry");
                    Predicate p2 = cb.equal(custIndustry.as(String.class), customer.getCustIndustry());
                    list.add(p2);
                }
                Predicate[] predicates = list.toArray(new Predicate[0]);
                return cb.and(predicates);
            }
        };
        List<Customer> list = customerDao.findAll(spec);
}

7.3 cb查询方式总结

方法名称Sql对应关系
equlefiled = value
gt(greaterThan )filed > value
lt(lessThan )filed < value
ge(greaterThanOrEqualTo )filed >= value
le( lessThanOrEqualTo)filed <= value
notEqulefiled != value
likefiled like value
notLikefiled not like value

8.JPA多表查询

8.1 JPA实体的实现

一对一:在任意一方添加对方的对象属性
一对多:在一方添加多方的集合属性,在多方中添加一方的对象属性
多对多:在任意一方添加对方的集合属性

8.2ORM配置多表关系步骤

1. 添加关系注解:@OneToMany @ManyToOne @ManyToMany
2. 确定由哪方维护外键关系(另外一方放弃关系维护)
3. 在维护关系一方配置外键信息

8.3一对多配置

一方

@Entity
@Table(name="cst_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long custId;
    ...
    private String custSource;
   //一对多注解,一方放弃维护外键关系
    @OneToMany(mappedBy = "customer")
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();
}

多方

@Entity
@Table(name = "cst_linkman")
public class LinkMan {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long lkmId; //联系人编号(主键)
    ...
    private String lkmMemo;//联系人备注
   //多对一注解,多方维护外键关系,配置外键名称
    @ManyToOne
    @JoinColumn(name = "lkm_cust_id")
    private Customer customer;    
}
8.3.1 一般保存
@Test
@Transactional //配置事务
@Rollback(false) //不自动回滚
public void testAdd() {
    //创建一个客户
    Customer customer = new Customer();
    customer.setCustName("百度");
	//创建一个联系人
    LinkMan linkMan = new LinkMan();
    linkMan.setLkmName("小李");
	//维护外键关系
    linkMan.setCustomer(customer);
    //保存客户
    customerDao.save(customer);
    //保存联系人
    linkManDao.save(linkMan);
}
8.3.2 级联保存
//级联添加:保存一个客户的同时,保存客户的所有联系人
@Test
@Transactional //配置事务
@Rollback(false) //不自动回滚
public void testCascadeAdd() {
    Customer customer = new Customer();
    customer.setCustName("百度1");
    LinkMan linkMan = new LinkMan();
    linkMan.setLkmName("小李1");
    //维护外键
    linkMan.setCustomer(customer);
    //级联保存
    customer.getLinkMans().add(linkMan);
    customerDao.save(customer);
}
8.3.3 级联删除
//级联删除:删除客户的同时,删除该客户的所有联系人
@Test
@Transactional //配置事务
@Rollback(false) //不自动回滚
public void testCascadeRemove() {
    //1.查询1号客户
    Customer customer = customerDao.findOne(1L);
    //2.删除1号客户
    customerDao.delete(customer);
}

8.4 多对多配置

多方

@Entity
@Table(name = "sys_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long userId;
    private String userName;
    private Integer age;
    //配置多对多关系,User方维护外键关系
  	@ManyToMany
    @JoinTable(name="user_role",joinColumns = {@JoinColumn(name ="user_id" )},
               inverseJoinColumns = {@JoinColumn(name="role_id")})
    private Set<Role> roles = new HashSet<Role>();
    
}

另一多方

@Entity
@Table(name = "sys_role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long roleId;
    private String roleName;
    //配置多对多关系,Role方放弃维护外键关系
    @ManyToMany(mappedBy = "roles")  //配置多表关系
    private Set<User> users = new HashSet<User>();
}
8.4.1 一般保存
// 保存一个用户,保存一个角色
@Test
@Transactional
@Rollback(false)
public void  testAdd() {
    User user = new User();
    user.setUserName("小李");
    Role role = new Role();
    role.setRoleName("java");
    //用户维护外键关系
    user.getRoles().add(role);
    userDao.save(user);
    roleDao.save(role);
}
8.4.2 级联保存
//测试级联添加(保存一个用户的同时保存用户的关联角色)
@Test
@Transactional
@Rollback(false)
public void  testCasCadeAdd() {
    User user = new User();
    user.setUserName("小李");
    Role role = new Role();
    role.setRoleName("java");
    //配置用户到角色关系,可以对中间表中的数据进行维护     1-1
    user.getRoles().add(role);
    //保存客户,级联保存角色
    userDao.save(user);
}
8.4.3 级联删除
//案例:删除id为5的用户,同时删除他的关联角色
@Test
@Transactional
@Rollback(false)
public void  testCasCadeRemove() {
    //查询5号用户
    User user = userDao.findOne(5L);
    //删除5号用户
    userDao.delete(user);
}

8.5. 级联配置总结

//在关系注解上添加如下属性
增:CascadeType.PERSIST
删:CascadeType.REMOVE
改:CascadeType.MERGE
所有:CascadeType.ALL

9. 多表之间的查询

9.1 对象导航图查询

通过实体类中的关联属性查询关联数据

一方查询多方

@Test
@Transactional // 解决在java代码中的no session问题
public void  testQuery1() {
    //查询id为1的客户
    Customer customer = customerDao.getOne(6L);
    //对象导航查询,此客户下的所有联系人
    Set<LinkMan> linkMans = customer.getLinkMans();
}

多方查询一方

@Test
public void  testQuery3() {
    LinkMan linkMan = linkManDao.findOne(6L);
    //对象导航查询所属的客户
    Customer customer = linkMan.getCustomer();
}

一方查询多方,默认是懒加载

多方查询一方,默认是立即加载

配置对象导航图加载方式

//在关系注解上添加如下属性
立即加载:fetch=FetchType.EAGER
懒加载:fetch=FetchType.LAZY

9.2 Specification查询

@Test
public void testFind() {
 Specification<LinkMan> spec = new Specification<LinkMan>() {
  public Predicate toPredicate(Root<LinkMan> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        /**
         * Join代表连接查询,通过root对象获取
         * JoinType.INNER
         * JoinType.LEFT
         * JoinType.RIGHT
         */
        Join<LinkMan, Customer> join = root.join("customer", JoinType.INNER);
        return cb.like(join.get("custName").as(String.class),"百度");
   }
 };
 List<LinkMan> list = linkManDao.findAll(spec);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值