MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.4
mysql
mysql-connector-java
5.1.48
//1,创建SqlSessionFactory对象,线程非安全,用来产生SqlSession
//2,创建SqlSession,用来执行sql
//3, 定位SQL: namespace的值+id的值,可以只传入id,但是,如果在mybatis的环境中有多个 相同id的映射名称,就会报错。
//4,解析结果并打印
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory session = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = session.openSession();
Listlist = sqlSession.selectList("hello.get"); for (User u : list) {
System.out.println(u);
}
select * from user
当数据库的字段名和对象的属性名一致时,可以用简单属性resultType。
但是当数据库中的字段名称和对象中的属性名称不一致时,就需要resultMap属性。
例子:
#{}是预编译处理,${}是字符串替换。
Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋值;
Mybatis 在处理${}时,就是把${}替换成变量的值。
总结:
使用#{}进行预编译处理,可以有效的防止 SQL 注入攻击,提高系统安全性。
注意:order by后面的关键字必须用${}
传递表名时必须用${}
其他情况能使用#{}就不要使用${}
(1)xml文件
#spring整合数据源 最快的数据源
spring:
datasource:
#使用高版本驱动时使用cj
#serverTimezone=GMT%2B8 东8区 %2B +号
#&useUnicode=true&characterEncoding=utf8 是否开启unicode编码/utf-8
#&autoReconnect=true 断线是否重连
#&allowMultiQueries=true 是否允许批量操作
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
#如果密码以数字0开头,则使用""号包裹 "0123456"
password: root#SpringBoot整合Mybatis配置
mybatis:
#设置别名包
type-aliases-package: com.jt.pojo
#加载映射文件
mapper-locations: classpath:/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
(2)为接口创建代理对象
@Mapper
@MapperScan("com.jt.mapper")
(3)实现数据查询时有2种Sql的写法
将所有的Sql语句都写到xml 映射文件中. (万能操作方式)
可以将Sql语句通过注解的方式标识在接口方法中.(只适用于简单操作)
@select @insert @update @delete
使用MP主要完成单表的CURD操作简化开发
(1) 说明:
注解:
(2)Mapper继承公共的接口BaseMapper,添加泛型对象
(3)创建条件构造器,封装where条件(默认的关系链接符 and)
逻辑运算符 > gt, < lt, = eq, >= ge, <= le, != ne
like:leftlike,rightlike
关键字: order by 排序 默认规则: 升序 asc 降序 desc
QueryWrapper queryWrapper = new QueryWrapper();
(4)利用MP实现分页查询查询
PageResult
@Data @Accessors(chain = true) public class PageResult { private String query; //查询的key private Integer pageNum; //页数 private Integer pageSize; //条数 private Long total; //总数 private Object rows; //分页后的结果 }
UserController /** * 需求: 利用分页展现用户user列表数据 * URL: /user/list GET方式 * 请求参数: http://localhost:8091/user/list?query=查询关键字&pageNum=1&pageSize=10 * 返回值: SysResult对象(PageResult) * */ @GetMapping("/list") public SysResult getUserList(PageResult pageResult){ pageResult = userService.getUserList(pageResult); return SysResult.success(pageResult); }
UserServiceImpl
/** * 利用MP的方式实现分页查询 * API说明:selectPage(arg1,arg2) * arg1: MP中的分页对象 固定的 * arg2: MP分页中的条件构造器 * @param pageResult * @return */ @Override public PageResult getUserList(PageResult pageResult) { //1.定义MP的分页对象 arg1:页数 arg2:行数 IPage iPage = new Page(pageResult.getPageNum(),pageResult.getPageSize()); //2.构建查询条件构造器 QueryWrapper queryWrapper = new QueryWrapper(); //判断用户数据是否有效 有效true 无效false boolean flag = StringUtils.hasLength(pageResult.getQuery()); queryWrapper.eq(flag,"username",pageResult.getQuery()); //经过MP分页查询将所有的分页数据(total/结果/页面/条数)封装到iPage对象 iPage = userMapper.selectPage(iPage,queryWrapper); //从分页对象中获取分页@Transactional后的总记录数/结果 return pageResult.setTotal(iPage.getTotal()).setRows(iPage.getRecords()); }
MP配置类
//命名规则:类似于配置文件 则把这个类称之为"配置类" 一般Config接我 @Configuration //标识是一个配置类(代替之前的xml文件) public class MybatisPlusConfig { //铺垫:xml中通过标签管理对象,将对象交给Spring容器管理//配置类:将方法的返回值交给Spring容器管理 @Bean注解 /** * 关于MP分页规则说明 * 规则:需要设定一个拦截器,将分页的sql进行动态的拼接 * sql规则:现在的sql都支持sql92标准 * */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MARIADB)); return interceptor; } }
(5)MP实现自动填充
//pojo基类,完成2个任务,2个日期,实现序列化 @Data @Accessors(chain=true) public class BasePojo implements Serializable{ @TableField(fill = FieldFill.INSERT) private Date created; //表示入库时需要赋值 @TableField(fill = FieldFill.INSERT_UPDATE) private Date updated; //表示入库/更新时赋值. }
MP对外暴露了一个自动填充的接口MetaObjectHandler ,用户只需要实现该接口,并且重写其中的方法。即可以实现自动填充的功能。 @Component //将对象交给Spring容器管理 不属于C/S/M public class MyMetaObjectHandler implements MetaObjectHandler { // 入库操作时调用created/updated /** * setFieldValByName(arg1,arg2,arg3) * arg1 自动填充的字段名称 * arg2 自动填充的值 * arg3 metaObject(固定写法) */ @Override public void insertFill(MetaObject metaObject) { //设定时间变量 Date date = new Date(); this.setFieldValByName("created", date, metaObject); this.setFieldValByName("updated", date, metaObject); } //更新操作时调用updated @Override public void updateFill(MetaObject metaObject) { this.setFieldValByName("updated", new Date(), metaObject); } }
例子1:
string wildcardname = “%smi%”;
listnames = mapper.selectlike(wildcardname);
例子2
string wildcardname = “smi”;
listnames = mapper.selectlike(wildcardname);
Dao接口的工作原理是JDK动态代理,Mybatis运行时,使用JDK动态代理为Dao接口生成代理对象。
一级缓存:
Mybatis支持缓存,但在没有配置的情况下,默认情况下它只启用一级缓存。级别1缓存只对相同的SqlSession启用。因此,如果SQL参数一模一样,我们使用相同的SqlSession对象调用映射方法,通常只执行SQL一次,因为第一个查询使用SelSession MyBatis将把它放在缓存中,和将来查询,如果没有声明需要刷新,如果缓存中没有,SqlSession将获取当前缓存的数据,并且不会再次向数据库发送SQL。
二级缓存:
MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。二级缓存与一级缓存其机制相同,默认也是采用PerpetualCache,HashMap存储,不同在于其存储作用域为Mapper(Namespace),并且可自定义存储源,如Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置
接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。
接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上@Select、@Update等注解,里面包含Sql语句来绑定;另外一种就是通过xml里面写SQL来绑定,在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。
总结:当Sql语句比较简单时候,用注解绑定,当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。
JDBC是java提供了一套专门用于和数据库对接的api,java.sql.*,其规范了如何和数据库进行对接,实现由各数据库厂商进行各自的实现和扩展。学习JDBC重点在学习如何使用其api。
MyBatis框架是轻量级封装了JDBC,我们已经看不到这些api,连接connection、语句preparedstatement、结果集ResultSet,而关注的是mybatis框架体系如何去使用,一旦写好,我们关注的是java对象。