• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

spring-data学习上

武飞扬头像
爱码~
帮助1

  • spring data
spring data是spring中的一个子项目,统一和简化各种类型的持久化操作,它有一套api可以对关系型数据库和非关系型数据库进行crud
spring data支持了很多模块支持多种数据库的操作,
  • spring data jpa
spring data jpa 是spring在jpa规范上的基础上封装了一套jpa应用框架,
- jpa
jpa是java提供的opm框架 对象关系映射框架,jpa是一套规范接口,不提供实现,实现是由第三方来实现,jpa的实现有Hibernate,openJPA
只需要满足JPA规范就可以了,
jpa操作数据库的方式是使用EntityManage中的方法,mysql是面向sql来查询,jpa是通过@onetomany @manytomany等注解来配置对象关系完成多表
查询
  • 实例展示
- 创建一个springBoot项目
- 导入依赖
<!--springboot依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--springdata jpa的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--mysql连接驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
- 配置文件中添加spring 数据源信息 和jpa 连接信息
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/bjsxt
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
  # 配置spring data jpa  
  jpa:
    database: mysql 数据类型
    show-sql: true  是否显示sql语句
    generate-ddl: true 是否能够自动建表  ddl 数据定义语言
    hibernate: 
      ddl-auto: update  根据实体类自动建表
      # 解决实体类使用驼峰命名法来与数据库字段进行映射匹配
      naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
- 创建pojo
1 注解 @Entity 代表是一个实体类 @table(name = "")与数据库表关联映射 @ id是一个注解列
- 编写dao层接口
repository 接口 这个接口不用写实现类 直接继承两个接口
1 jpaRepository<实体类类型,主键类型> 该接口提供了基本的crud操作
2 jpaSpecificationExecutor<实体类类型> 该接口提供了复杂的查询操作
/** repository表示是一个dao层
 *  该层需要继承两个接口
 *  1 jpaRepository<实体类类型,主键类型> 该接口提供了基本的crud
 *  2 jpaSpecificationExecutor<实体类类型> 该接口提供了复杂的查询操作
 *  注意只需要继承不需要写实现
 *  repository中常用的方法,
 *  1 save 新增 修改 加id 是修改 否则是新增
 *  2 delete 删除
 *  3 findOne 根据id查询
 *  4 findAll 查询全部
 * */
 - 测试类查询
 Student student1 = new Student(1, "大娃", 8, "男");
        Student save = student.save(student1);
        System.out.println(save);
        //student.deleteById(1);
        List<Student> all = student.findAll();
        all.stream().forEach(System.out::println);
        Optional<Student> byId = student.findById(1);
        Student student = byId.get();
        System.out.println("查询结果");
        System.out.println(student);
学新通
  • 寻找repository层的实现类
在repository层中的接口是不需要是实现类的并且没有方法都知道他是接口多继承与 jpaRepository和jpaSpecificationExecutor
但是他们都是接口继承接口,没有看到实现类啊
1 创建一个StudentRepository接口 作为操作数据库的类
2 继承 japRepository接口来调用里面的抽象方法来操作实体类
2 在spring data jpa框架中有一个jdkDynamicAopProxy类中invoke()方法来创建一个simpleJpaRepository对象
3 其实simpleJapRepository类是JpaRepository接口
4 simplejaprepository类调用了jap框架中的enityManager类
5 enitymanager类封装了hibernate框架
6 hibernate框架操作jdbc驱动数据库库
所以在调用studentRepository接口中的继承抽象方法时,是会在内存中创建出实体类的

  • spring data jpa 查询方式
- 使用jparepository接口中的方法
1 count() 查询总条数
2 existsByid() 查询记录是否存在
3 getone/findByid 根据id查找数据
4 findByid 立即加载
5 getone 延迟加载 添加事务支持@Transcational
- 示例
    @Transactional //添加事务因为getone是延迟加载
    @Test
    public void t2(){
        long count = student.count();
        System.out.println("总数:" count);
        System.out.println(student.existsById(1));
        Student one = student.getOne(1); //延迟加载
        Optional<Student> byId = student.findById(1); //立即加载
        System.out.println(byId.get());
        System.out.println(one);

    }
学新通
  • 使用jpql进行查询
- 简单的数据查询当然是可以进行封装了,但是经常是遇到复杂的sql查询该怎么办呢?
- 使用jpql方式来进行复杂查询
1 在repository接口中自定义抽象方法,方法上加上@Query("JPQL") 就是没有select 
2 jpql中传递参数时使用 ?参数索引 来作为占位符的 参数列表的顺序就是索引 从1开始
3 使用dml时需要在接口方法上添加@modifying还需要添加事务支持 @Transactional
- 示例
  @Query("FROM Student WHERE name like ?1")
    List<Student> findinfolikename(String name);

  @Query("FROM Student  WHERE name like ?1 and age like ?2")
  List<Student> findinfolikenameandage(String name, Integer age);

 @Modifying //dml操作必须添加modifying注解
 @Query("UPDATE Student set name = ?2 where id = ?1")
 void updateinfoname(Integer id,String newName);
-测试类
 	@Test
    @Transactional //修改方法必须要添加 事务
    @Rollback(false) //关闭回滚
    public void t4(){
        student.updateinfoname(4,"变异");
    }
学新通
  • 使用原生的sql进行查询
- 在dao层中定义方法,方法上添加注解@query(value = "sql",nativeQuery =true)
 属性中 nativeQuery属性的含义就是开启原生sql查询 valus是写sql
 - 示例
   @Query(nativeQuery = true,value = "select * from bz_student")
   List<Student> findallinfo();
  • 按照规则来命名给方法进行执行
- 意思就是说:只需要在dao层接口中按照spring data jpa 的命名规则命名方法,该方法就是可以自动实现,
- 规则如下:
1 查询方法以findBy开头 有条件就写在后面既可,条件就是属性用关键字来连接
2 And 关键字 多个条件查询 findBynameAndage    jpql=  where name = ?1 and age = ?2
2 Or 关键字是 或者的意思  findBynameOrage  jpql= where name = ?1 or age = ?2
3 Is/Equals  含义 =     findBynameIs/findBynameEquals	where name = ?1
4 Between  含义 区间    findByageBetween 	where age between ?1 and ?2
5 LessThan 含义 小于 	findByageLessThan	where age < ?1
6 LessThanEqual 含义 小于等于 findByageLessThanEqual	where age <= ?1
7 GreaterThan	含义 大于	findByageGreaterThan  where age > ?1
8 GreaterThanEqual	含义 大于等于 findByageGreaterThanEqual  where age >= ?1
9 After  含义 大于	findByageAfter   where age > ?1 
10 Before  含义 小于  findByageBefore    where age< ?1
11 IsNull  含义 是空  findByageIsNull	where age is null
12 IsNotNull/NotNull 含义 不为空   findByageIsNotNull  where age notnull
13 Like  含义 模糊查询	findByLike  where age like ?1
14 NotLike 含义 不包含	findByageNotLike 	where age nolike
15 OrderBy 含义 分组		findByageOrderBynameDesc  where age = ?1 order by name desc
16 Not 含义 不等于<>		
17 In 含义 in 
18 NotIn
19 TRUE
20 FALSE
21 IgnoreCase 含义 忽视大小写   

学新通
  • 使用JpaSpecificationExecutor接口中提供的方法进行复杂查询
- jpaspecificationExecutor接口中的方法
1 方法只有一个findAll() 
2 方法的参数对象有 Specification 查询条件对象	Pageable 分页条件对象		Sort 排序条件对象
- Specification条件构造器是一个接口 需要实现toPredicate方法来构建一个查询条件对象
- 注意 Specification是一个函数式接口 可以使用lamdba表达式来创建
- 注意toPredicate中有参数 1 root是用来获取想要以数据库中那个字段为条件返回的是一个path对象 用来存放字段
- cd对象是用来将字段和传过来的参数做关系映射 返回Predicate对象 就是真正where之后的条件
- 最后用findAll()方法来将接收Predcate对象
- 示例代码
	 @Test
    public void t7(){
        String queryname = "大娃";
        Integer queryage = 8;
        String querysex = "男";
        /** Specification接口是函数式接口
         * 用lamdba表达式来实现方法
         * 有三个参数
         * 1 root对象可以获取查询条件创建出path条件对象 就是查询的字段是有哪些
         * 2 cd对象是将root对象中的条件和查询条件做关系映射,把复杂条件创建成一个对象
         * */
        Specification<Student>  sc = (root,query,cd)->{
            //root对象将要进行条件处理的字段返回到path对象中
            Path<String> name1 = root.get("name");
            Path<Integer> age1 = root.get("age");
            Path<String> sex1 = root.get("sex");


            ArrayList<Predicate> list = new ArrayList<>();
            //用cd对象接收查询条件和条件字段进行关系映射处理
            if(queryname!= null){
                Predicate like = cd.like(name1, queryname);
                list.add(like);
            }
            if(queryage!= null){
                Predicate equal = cd.equal(age1, queryage);
                list.add(equal);
            }
            if(querysex!= null){
                Predicate equal1 = cd.equal(sex1, querysex);
                list.add(equal1);
            }
            Predicate[] predicates = list.toArray(new Predicate[list.size()]);
            Predicate and = cd.and(predicates);

            return and;

        };
        List<Student> all = student.findAll(sc);
        all.stream().forEach(System.out::print);
    }

学新通
  • pageable
 - pageable作用是进行数据分页,是一个接口,实现类是pageRquest,通过of(pagenum,pagesize)方法可以获取pageRequest
 - 将pageRequest对象作为参数传入到查询方法中就可使用
 - 示例
@Test
    public void t8(){
        PageRequest pageable = PageRequest.of(0,2);
        Page<Student> all = student.findAll(pageable);
        System.out.println(all.getTotalElements()); //总条数
        System.out.println(all.getTotalPages()); //总页数
        System.out.println(all.getNumber()); //当前页
        System.out.println(all.getSize());//页面大小
        all.getContent().stream().forEach(System.out::println);//当前数据
    }
  • Sort
- Sort 是一个类,创建一个Sort对象可以构建一个排序条件,将sort对象作为参数传入到方法中会将结果进行排序
- 示例
    @Test
    public void t9(){
//        单个条件
        Sort id = Sort.by(Sort.Direction.DESC, "id");
        List<Student> all = student.findAll(id);
        all.stream().forEach(System.out::println);
//        多个条件
        Sort.Order age = new Sort.Order(Sort.Direction.ASC, "age");
        Sort.Order id1 = new Sort.Order(Sort.Direction.DESC, "id");
        Sort by = Sort.by(age, id1);
        List<Student> all1 = student.findAll(by);
        all1.stream().forEach(System.out::println);

    }
学新通
  • 领域驱动设计DDD
- Spring Data Jpa是符合领域驱动设计项目的模式
	之前的项目进行数据操作时是使用数据驱动设计,每一个表对应一个dao层,如果一个业务涉及多张表,那么
	需要修改多张表,通过不同的dao层来操作,
	领域驱动模式是将整个业务设计成一个领域,该业务会涉及到多个类,多张表,涉及到的类称之为是聚合,
	聚合的操作可以通过一个聚合根来完成,这样可以看出领域驱动设计要比数据驱动设计要效率高很多
	可以了解到数据驱动是采用操作表来完成业务,而领域驱动是通过聚合根来完成数据的操作
- 示例
/** @Entity 表示这个实体类是jpa实体, 告诉jpa在程序中运行生成对应的表
 * @Table 设置实体类和数据库所对应的表名
 * @Id 标识这个类的属性为主键
 * @GeneratedValue 设置生成主键策略
 * @Column 表示属性对应的字段名进行设置
 * @Transient 标识属性非数据库表字段
 * @Temporal 时间日期类型
 * 多表关联
 * @JoinColumn 定义外键的字段名称 主要是配合@onetoone@Manytoone @onetomany
 *
 *
 *
 * */
@Entity
@Table(name = "bz_orderItem")
public class OrderItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private Long productId;
    @ManyToOne
    @JoinColumn(name = "order_id",referencedColumnName = "id")
    private Order order;

    public Integer getId() {
        return id;
    }

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

    public Long getProductId() {
        return productId;
    }

    public void setProductId(Long productId) {
        this.productId = productId;
    }

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }
}
==============
@Entity
@Table(name = "bz_order")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private  Integer id;
    private String mobile;
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "order_id",referencedColumnName = "id")
    private List<OrderItem> orderItemList = new ArrayList();

    public Integer getId() {
        return id;
    }

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

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public List<OrderItem> getOrderItemList() {
        return orderItemList;
    }

    public void setOrderItemList(List<OrderItem> orderItemList) {
        this.orderItemList = orderItemList;
    }
}
	===================
	 @Autowired
    private OrderRepository orderRepository;

    @Test
    public void t1(){
        Order order = new Order();
        order.setMobile("12512345678");
        OrderItem orderItem = new OrderItem();
        OrderItem orderItem1 = new OrderItem();

        orderItem.setProductId(1001L);
        orderItem1.setProductId(1002L);

        order.getOrderItemList().add(orderItem);
        order.getOrderItemList().add(orderItem1);

        orderRepository.save(order);


    }

学新通
  • spring data jdbc
spring data jdbc是spring data 的子模块,与spring data jpa 功能相似,
spring data jdbc 不提供缓存和延迟加载,它更加方便和简洁,但是可以支持集成其他orc框架
- 创建boot项目 
- 引入依赖 mysql驱动和springdata jpa
<!--springdata jpa的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--mysql连接驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

- 编写配置文件配置数据源
	spring:
  	datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/bjsxt
    username: rootroot
    password: 123456
- 	创建实体类
不使用@Entity只使用@Table和@Id
- 创建Repository接口,需要继承两个接口
1 CrudRepository<实体类类型,主键类型>
2 PagingAndSortingRepository<实体类类型,主键类型> 该公分页和排序
- 数据查询方式
1 通过crudRepository接口中的api进行查询
2 通过自定义sql来查询
- 示例
	@Query("select * from bz_teacher where address = :address")
    List<Teacher> findTeacherbyaddress(String address);
注意自定义sql查询要添加@Query注解来写sql,占位符用:来绑定参数
学新通
  • 使用JdbcTemplate
jdbcTemplate是spring对jdbc的封装之后提供的一个操作数据库的工具类,
当然spring data jpa 和spring data jdbc都是有的
jdbc不是面向对象单纯的为了执行sql语句而出现,不需要借助其他dao层方法直接开干
- 示例
1 直接注入
@Autowired
    private JdbcTemplate jdbcTemplate;
2使用方法
直接写sql,update(sql,参数) 执行dml语句
@Test
    void t4(){
        String sql = "insert into bz_teacher values(?,?,?)";
        Teacher teacher = new Teacher(2, "灰太狼", "狼堡");
        int update = jdbcTemplate.update(sql, teacher.getId(), teacher.getName(), teacher.getAddress());
        System.out.println(update);   
    }
==== 查询方法
@Test
    void t5(){
        /** queryForObject 该方法是执行sql返回一条数据,然后封装成一个实体类对象
         *  参数1 sql 参数2 用一个对象来将实体类和数据进行封装
         *  参数3 占位符参数
         * */
        String sql = "select * from bz_teacher where id = ?";
        Teacher teacher = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Teacher.class), 1);
        System.out.println(teacher);
        /** queryForObject(sql,结果类型,参数)
         * 执行查询结果是一行中的一列
         * */
        String sql2 = "select count(1) from bz_teacher";
        Object o = jdbcTemplate.queryForObject(sql2, Integer.class);
        System.out.println(o);
        /** 查询所有信息
         *  
         * */
        System.out.println("======");
        String sql3 = "select * from bz_teacher";
        List query = jdbcTemplate.query(sql3, new BeanPropertyRowMapper(Teacher.class));
        query.stream().forEach(System.out::println);


    }

学新通
  • Repository和Template两种方式对比
- 在spring data jdbc中查询数据有两种方式采用Repository和Template两种同样
spring data jap也是支持两种方式,
- 在Repository层中直接继承xxxRepository接口可以不必写实现类,可以通过方法来实现简单的crud操作
排序,分页,对于复杂的比较费力
- 直接使用xxxTemplate方式需要手写sql语句,对于复杂的运算可以手动控制
- 示例
@Test
    void t7(){
        String name = null;
        String address = "狼堡";

        String sqlquery = "select * from bz_teacher where 1=1 ";
        ArrayList<Object> condition = new ArrayList<>();

        if(name != null){
            sqlquery  = "and name = ?";
            condition.add(name);
        }
        if(address != null){
            sqlquery  = "and address = ?";
            condition.add(address);
        }
        List<Teacher> query = jdbcTemplate.query(sqlquery, new BeanPropertyRowMapper<>(Teacher.class), condition.toArray());
        query.stream().forEach(System.out::println);

    }

学新通
  • spring data jdbc集成mybatis框架
spring data jpa 使用必须集成jpa,hibernates框架 
spring data jdbc 可以直接使用但是也可以集成mybatis框架
注意 spring data jdbc 是不支持jpql, 延迟,缓存加载等jpa功能,
如果集成了mybatis框架可以使用缓存,延迟加载等
- 示例
1 导入依赖
 		<!--mybatis-starter-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
2 创建接口
@Repository
@Mapper
public interface TeacherPepositorymybatis {
    /** mybatis框架实现数据查询有两种方式
     * 1 配置文件
     * 2 注解sql
     * mybatis中的注解有@select @insert @Update @Delete
     * 用#{参数}
     * @One @Mant
     * */
    @Select("select * from bz_teacher where name = #{name}")
    List<Teacher> finallbyname(String name);

    /*  @Select("select * from t_student")
        @Results(value = {
        @Result(column="id", property="id", id=true),
        @Result(column="name", property="name"),
        @Result(column="age", property="age"),
        @Result(column="gender", property="gender"),
        @Result(column="cid", property="cid"),
        @Result(property="clazz", one=@One(select="com.bjsxt.mapper.ClazzMapper.selById"), column="cid")  })
        List<Student> sel();
        }
    * */
    Teacher finalAll();
}
3 配置文件设置
		#配置文件映射地址 如果接口和配置文件不在同一个包下需要配置这个路径
		mybatis:
  		mapper-locations: classpath:mybatis/*.xml

4 编写mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://www.mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.springdata.jdbc.repository.TeacherPepositorymybatis">
    <!-- 动态接口映射要素
         1 namespace命名空间是接口的全路径
         2 标签id和方法名一致
         规范 也可以将配置文件和接口放到同一个包下,接口名字和配置文件名字一样
    查询-->
    <select id="finalAll" resultType="com.bjsxt.springdata.jdbc.pojo.Teacher">
      select * from bz_teacher
    </select>

</mapper>
 
学新通
  •  

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgaegfc
系列文章
更多 icon
同类精品
更多 icon
继续加载