数据库访问中间件

SpringBoot整合MyBatis

Mybatis回顾

一、配置

MyBatis的配置

	设置mybatis的配置文件路径,默认是在resources的目录
mybatis.config-location=classpath:mybatis/mybatis-config.xml
	设置mybatis下面的mapper映射文件路径,默认是在resources的目录
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
	设置项目中实体类包路径;
mybatis.type-aliases-package=com.study.springbootmybatis.entity
	设置缓存失效
spring.thymeleaf.cache=false
	展示sql语句
logging.level.com.study.springbootmybatis.repository.UsersDao=debug

测试

@SpringBootTest
class SpringbootMybatisApplicationTests {
    @Resource
    UsersDao usersDao;
    @Test
    void contextLoads() {
        System.out.println(usersDao.findAll());
    }
}

注解

public interface UsersDao {
	非注解,在mapper中配置
    List<Users> findAll();
    Users findById(int id);
    注解
    @Select("select id,username,password,name from users where name like #{name}")
    Users findByName(String name);

}

零配置

在properties中删除相关xml配置,删除实体类路径。
在资源中删除xml文件
在dao接口中删除非注解方法。

Springboot结合rest和mybatis完成业务操作

	这里是演示一对多中的多
    @Select("select * from Product where uid=#{uid}")
    Product findByUid(int uid);
演示一对多中的1,这里是根据id来查users对象,那么我们可以结合ProductRepository来一次性把对应的product也查出来
property指的是在Users实体类中一对多中的多的属性名,column代表的是把users表中的那个字段作为后面查询的条件,many指的是查询是一对多还是一对一
    @Select("select * from Users where id=#{id}")
    @Results({
            @Result(
                    property = "products",column = "id",many = @Many(select = "com.study.springbootmybatis.repository.ProductRepository.findByUid")
            )
    })
    Users findUsersById(int id);

Spring Data Jpa 的简介和快速入门

一、Spring Data

简介

Spring Data是为了简化构建基于Spring框架应用的数据访问技术。包括对关系数据库、非关系数据库、Map-Reduce框架、云数据服务等访问支持。它为我们提供使用统一的API标准来对数据访问层进行操作,这套标准包含了CRUD(创建、获取、更新、删除)、查询、排序和分页的相关操作。

特点

  • 支持对象关系映射:
    • 具备ORM框架的对象关系映射功能
  • 统一的Repository接口
    • Repository<T,ID extends Serializable>: 统一接口
    • CrudRepository<T,ID extends Serializable> 基本CRUD操作
    • PagingAndSortingRepository<T,ID> extends Serializable>:基本CRUD及分页
  • 统一的数据访问模板类xxxTemplate
    • 如:MongoTemplate、RedisTempIate等

二、JPA

简介

  • Jpa是 java持久化规范,它为Java开发人员提供一种对象/关联映射工具来管理Java应用中的关系数据。它的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate、TopLink、JDO等ORM框架各自为营的局面
  • Jpa是在充分吸收了现有的Hibernate、TopLink、JDO等ORM框架的基础上发展而来的,具有易于使用、伸缩性强等优点。
  • JPA是一套规范,不是一套产品,那么像Hibernate、TopLink、JDO它们是一套产品,如果说这些产品实现了这个JPA规范,那么我们就可以称他们为JPA的实现产品。

:jdbc是数据访问规范

Spring Data 与 JPA 的关系

在这里插入图片描述

Spring Data JPA 工作原理

在这里插入图片描述

快速入门

jpa配置
spring:
  jpa:
    show-sql: true  //支持sql输出
    database: mysql  //数据库类型
    hibernate:
      ddl-auto: update  //自动生成开启,让表数据会自动跟随entity类的变化而变化
    properties:
      hibernate:
        format_sql: true   //format一下SQL进行输出
    database-platform:  org.hibernate.dialect.MySQL5InnoDBDialect
repository
public interface UserRepository extends JpaRepository<TUser, Integer> {
    TUser findTuserByUsernameLike(String username);
}

Spring Data JPA 的基本使用

一、基于单表的SQL操作

单表SQL操作-使用关键字拼凑方法

关键词样例JPQL代码段
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstname,findByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1(附加参数绑定%)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1(与前置绑定的参数%)
ContainingfindByFirstnameContaining… where x.firstname like ?1(包含参数绑定%)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection ages)… where x.age not in ?1
TRUEfindByActiveTrue()… where x.active = true
FALSEfindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)

示例

1、查询出年龄小于等于22岁的人;
    List<Person> findAllByPageIsLessThanEqual(Integer age);
2、查询出年龄在20-22岁之间并且性别是男的人
    List<Person> findAllByPageBetweenAndPsexEquals(Integer lowage,Integer highage,String sex);
3、查询出已经结婚并且性别是男的人
    List<Person> findAllByGetmarriedIsTrueAndPsexEquals(String psex);
  • 实体类属性名不要出现is×xx、get)(xx的名称,会导致关键字拼凑出错
  • 实体类属性名中间只要出现了大写字母,就会导致数据库的字段名有下划线隔开,比如你使
  • 用isMarried属性名,那么实体类的字段名就会变成is一married,这样容易导致找不到值
  • 属性名类型是b[ean类型的在某些数据库中会变成bit(1)类型,其中0为false,1为true
    实体类
@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Person {
    @Id
    @GenericGenerator(name = "myuuid",strategy = "uuid") 主键生成策略
    @GeneratedValue(generator = "myuuid")
    private String pid;
    @Column(unique = true)
    private String pname;
    @Column
    private String psex;
    @Column
    private Integer page;
    @Column
    private boolean getmarried;
}

关键拼凑字无法解决的问题

  • 实体类的是属性名与表的字段名无法映射,导致关键字找不到
  • CRUD操作方式比较另类或者是你不想用关键字的写法
  • 涉及到了多表操作

使用注解手写sql语句

  • 使用SQL语句来书写SQL
  • 使用HQL语句来书写SQL
相关操作
  • 按照pname来模糊删除
  • 查询出年龄是20.22岁的并且性别是女的人
  • 使用spe[表达式来演示用户的登陆
注意事项
  • 如果是删改操作,需要加@Modifying和@Transactional注解
  • 如果是SQL语句,请在@Query注解上加上NativeQuery=true的属性
  • 传参的方式有两种:
    • 使用?+数字的方式,数字从1开始,代表第几个参数
    • 使用:+参数名的方式,这种方式最好配合@Param注解一起使用
示例
    @Transactional
    @Modifying
   /示例1 @Query(value = "delete from Person where pname like ?1")  1代表匹配第一个参数
    void deleteByName(String pname);/
    或者这样↓  推荐使用这种
   /示例2 @Query(value = "delete from Person where pname like :pname")
    void deleteByName(@Param("pname")String pname); /
   示例3 @Query(value = "delete from Person where pname like %:pname%")
    void deleteByName(@Param("pname")String pname);


   默认是HQL语句,如果打sql语句需要多一个变量
    /@Query(value = "select * from person where page between 20 and 22 and psex='女',",nativeQuery = true)/
    @Query(value = "select p from Person p where p.page between 20 and 22 and p.psex='女'")
    List<Person> findPerson();


 	使用SPEL表达式来完成person表的修改操作
    @Modifying
    @Transactional
    @Query(value = "update person set pname=:#{#person.pname},psex=:#{#person.psex},page=:#{#person.page} where pid=:#{#person.pid}",nativeQuery = true)
    void updatePerson(@Param("person")Person person);

二、JPA逆向工程及多表SQL操作

  • 使用数据接口
    • 构建一个数据接口,里面的抽象方法就是SQL语句的查询结果的字段对应的getXXX的抽象方法。
  • 使用集合 (推荐)
    • 直接使用List/Map等集合嵌套的方式来获取到接收数据
  • 使用VO(view object)
    • 单独构建一个跟页面展示数据对应的VO的实体类来接接收数据

利用idea右侧数据库工具连接上数据库
利用Jpa生成实体类

  • project structure - > Modules -> 点击“+” -> 选择Jpa, -> 点击右侧“+” -> 选择第一个persistence.xml。-> 点击ok
  • 在界面左侧出现persistence 标题卡 选择唯一的那个项目,右键选择Generate persistence Mapping -> 选择By DataSource Schema ,选择数据库,选择实体类生成所在的包。为想要生成table打上勾,实体类前缀 后缀为空。最后选择yes。

示例

    联表查询-根据书名来查该书籍的拥有者
    @Query(value = "select p from Person p inner join Book b on p.pid=b.pid where b.bname=:bname")
    Person findPersonByBname(@Param("bname") String bname);

    联表查询-根据用户id来查询person和book  (通过数据接口的方式)
    @Query(value = "select p.pid as pid, p.pname as pname, p.psex as psex, p.getmarried as getmarried," +
            "b.bid as bid,b.bname as bname, b.bprice as bprice from Person p inner join Book b on p.pid =b.pid " +
            "where p.pid=:pid")
    List<PersonInfo> findAllInfo(@Param("pid") String pid);

    联表查询-根据用户id来查询person和book  (通过简单集合的方式)
    @Query(value = "select p.pid as pid, p.pname as pname, p.psex as psex, p.getmarried as getmarried," +
            "b.bid as bid,b.bname as bname, b.bprice as bprice from Person p inner join Book b on p.pid =b.pid " +
            "where p.pid=:pid")
    List<Object> findAllInfo1(@Param("pid") String pid);

    联表查询-根据用户id来查询person和book  (通过嵌套集合的方式)
    @Query(value = "select p.pid as pid, p.pname as pname, p.psex as psex, p.getmarried as getmarried," +
            "b.bid as bid,b.bname as bname, b.bprice as bprice from Person p inner join Book b on p.pid =b.pid " +
            "where p.pid=:pid")
    List<Map<String, Object>> findAllInfo2(@Param("pid") String pid);

上述示例用到的数据接口

public interface PersonInfo { //数据接口
    String getPid();
    String getPname();
    String getPsex();
    String getPage();
    String getGetmarried();
    Integer getBid();
    String getBname();
    double getBprice();
}

测试


		数据接口的方式 
		List<PersonInfo> allInfo = personRepository.findAllInfo("40280981727e7c0401727e7c11210002");
        for (PersonInfo info : allInfo) {
            System.out.println(info.getPid()+","+ info.getPname() +","+ info.getPsex() +","+ info.getPage()  +
                    ","+ info.getGetmarried() +","+ info.getBid() +","+ info.getBname() +","+ info.getBprice() );
        }
        简单集合的方式
        List<Object> allInfo1 = personRepository.findAllInfo1("40280981727e7c0401727e7c11210002");
        Object[] o =(Object[]) allInfo1.get(0);
        System.out.println(Arrays.toString(o));/

        嵌套集合的方式 List<Map>
        System.out.println(personRepository.findAllInfo2("40280981727e7c0401727e7c11210002"));

注: 多表SQL操作注意事项
- 使用数据接口的方式来接受查询的字段时要注意,必须要为要查询的字段名起别名,否则会无法取到

三、 QueryDSL的简单介绍

简介

  • QueryDSL仅仅时一个通用的查询框架,专注于通过JavaAPI构建类型安全的Sql查询,也可以说QueryDSL是基于各种ORM框架以及Sql之上的一个通用的查询框架,QueryDSL的查询,类似于SQL查询,很全面只不过一个是用SQL一个是用代码来代替SQL

建议

  • 建议 单表乃至简单的多表操作,都不推荐使用QueryDSL‘,使用JPA自带API简介又效率,但是涉及太复杂的查询,推荐使用QueryDSL

QueryDSL官网
操作总结:
在这里插入图片描述

Springboot中的分页

一、使用JPA自带的Pageable接口分页

Pageable

简介

Pageable分页是SpringDataJPA默认提供的分页功能,直接继承JpaRepository就获得了该分页功能;

分页模型
FirstPrevious123456NextLast
  • 获取元素总数;
  • 获取总页数;
  • 获取当前页数;
  • 获取当前页的内容;
  • 是否有上一页、上一页;
  • 是否有下一页、下一页的内容;
  • 首页、尾页的内容;
API

JpaRepository 接口继承了 PagingAndSortingRepository接口
PagingAndSortingRepository接口有findAll方法来获取Page对象,但是需要Pageable接口作为方法参数传入。

findAll(Pageable pageable)
Returns a Page of entities meeting the paging restriction provided in the Pageable object.

static PageRequest of(int page, int size)
Creates a new unsorted PageRequest.

方法参数用接口Pageable的子类PageRequest。

示例
public String findAll(ModelMap modelMap, @RequestParam(defaultValue = "0", value = "pageNum") int pageNum){
------------------------------当前页数 每页元素数量  排序并且按照薪资倒叙
Pageable pageable = PageRequest.of(pageNum, 5, Sort.Direction.DESC, "sal");
Page<Emp> pages = empRepository.findA11(pageable);

当前页数
System.out.println("当前页数: "+pages.getNumber());
页数
System.out.println("总页数: " + pages.getTotalPages());
总数量
System.out.println("总数量: " + pages.getTotalE1ements());
所有数据
System.out.println("所有数据:" + pages·getContent());
是否有上一页
System.out.println("是否有上一页:" + pages·hasprevious());
是否有下一页
System.out.println("是否有下一页:" + pages·hasNext());
当前页的上一页
System.out.println("当前页的上一页:" + (pages.hasPrevious()? pages.previousPageable().getPageNumber():
                pages.getPageable().getPageNumber()));
当前页的下一页
System.out.println("当前页的下一页:" + (pages.hasNext()?pages.nextPageable().getPageNumber():
                pages.getPageable().getPageNumber()));
modelMap.addAttribute("pages", pages);
return "list"

二、使用Mybatis和PageHelper插件进行分页

配置

pagehelper.helperDia1ect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSq1

API

方法含义
Pagelnfo list结果集
Pagelnf0.pageNum当前页码
Pagelnf0.pageSize当前页面显示的数据条目
Pagelnfo.pages总页数
Pagelnfo.total数据的总条目数
Pagelnf0.prePage上一页
Pagelnf0.nextPage下一页
Pagelnf0.isFirstPage是否为第一页
Pagelnf0.isLastPage是否为最后一页
Pagelnf0.hasPreviousPage是否有上一页
PageHelper.hasNextPage是否有下一页

示例

public String findAll(ModelMap modelMap, @RequestParam(defaultValue = "0", value = "pageNum") int pageNum){
	PageHelper.startPage(pageNum, 5);
   List<Emp> emps = usersRepository.findAll();
   PageInfo<Emp> pages = new PageInfo<>(emps);
   modelMap.addAttribute("pages", pages);
   return "list";
}

资料

GitHub地址
配置说明
API文档

三、两种分页的区别

Pageable

  1. JPA自带的分页方式,不需要添加额外的支持及配置;
  2. 页数是从0开始,从size-1为止;
  3. 单表、简单的多表操作分页排序使用它方便快捷;

PageHelper

  1. 第三方插件,需要添加对应的依赖以及进行相关配置;
  2. 页数是从1开始,从size为止;
  3. 只支持Mybatis(由于PageHeIper是根据离他最近的一个sql执行,而jpa刚好是自动生成sql,所以PageHelper最好用mybaties。如果必须用就jpa的话需要引入entitymanager + Query查询)
  4. 复杂的查询使用PageHelper可以让你更加方便;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值