SSM
MyBatis(ibatis)
一,ORM框架是什么
- mybtis参考
Object Relation Mapping
对象(java对象)关系(数据库表)映射- 让操作数据库关系表,就像操作对象一样
二,MyBatis 是什么
- 它是一款半自动的ORM持久层框架,具有较高的SQL灵活性
- 区别于全自动ORM
hibernate
它需要手动编写SQL - 实现Java工程与数据库一定程度上的分离,简化JDBC
MyBatis
本是apache
开源项目iBatis
,2010 从Apache software foundation
迁到Google code
更名MyBatis
2013年 迁移到GitHub
三,需要那些知识储备
- JDBC
- MySQL
- Java基础
- Maven
- Junit
四,学习要点
- MyBatis 使用环境搭建
- 使用映射配置实现CURD
- 动态SQL SQL语句构建
- 多表查询
- 日志
- MyBatis 缓存机制
五,如何配置MyBatis环境
-
官方网站
-
使用步骤
-
下载mybatis相关的jar,在上面的中文网站也是可以下载的 下载地址
-
mybatismybatis-3.5.2.zip
- mybatis
- 它所依赖的jar
-
mybatis 源码 mybatis-3-mybatis-3.5.2.zip
-
maven
<!--junit test--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <!-- mysql driver--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.23</version> </dependency> <!-- 日志--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
-
编写导入配置文件 并测试环境
-
mybatis主配置文件(mybatis-config.xml)
-
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--引入properties文件 --> <properties resource="database.properties" /> <!--配置log4j--> <settings> <setting name="logImpl" value="LOG4J" /> </settings> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>
-
部分情况下
${url}
应该写成${jdbc.url}
否则url
会不识别(换个名字也可以) -
xml中
&
不识别需要转义&
-
database.properties
-
driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/stu_new_manager?useUnicode=true&characterEncoding=utf-8 username=root password=123456
-
log4j.properties
-
-
### 设置Logger输出级别和输出目的地 ### debug更详细,如果设为info那么打印出的表数据遇到字符串就不显示,此外还有logfile log4j.rootLogger=debug,stdout ### 把日志信息输出到控制台 ### log4j.appender.stdout=org.apache.log4j.ConsoleAppender #log4j.appender.stdout.Target=System.err log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout ### 把日志信息输出到文件:jbit.log ### #log4j.appender.logfile=org.apache.log4j.FileAppender #log4j.appender.logfile.File=jbit.log #log4j.appender.logfile.layout=org.apache.log4j.PatternLayout #log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n ###显示SQL语句部分 #log4j.logger.com.mybatis=DEBUG #log4j.logger.com.mybatis.common.jdbc.SimpleDataSource=DEBUG #log4j.logger.com.mybatis.common.jdbc.ScriptRunner=DEBUG #log4j.logger.com.mybatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG #log4j.logger.java.sql.Connection=DEBUG #log4j.logger.java.sql.Statement=DEBUG #log4j.logger.java.sql.PreparedStatement=DEBUG
-
-
创建数据库表
-
创建实体类最好与数据库字段一致
-
创建接口CRUD方法
package com.itCast.dao; import com.itCast.domain.User; import java.util.List; public interface UserMapper { List<User> getUserList(); }
-
创建接口实现类
-
原来的方式 :
com.itCast.dao.impl.UserDaoImpl
实现类com.itCast.dao.UserDao
interface
-
mybatis的方式
com.itCast.dao.UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace 接口全类名 id 接口方法名 resultType 返回值类型--> <mapper namespace="com.itCast.dao.UserMapper"> <select id="getUserList" resultType="com.itCast.domain.User"> select * from user; </select> </mapper>
-
-
六,MyBatis 学习要点展开
一,基础配置使用
-
当参数过多可以使用Map 集合比较灵活
- key-value 在sql中取出key
#{u_name}
- 多个参数Map
- 对象的参数是固定的不能改变
- key-value 在sql中取出key
-
模糊查询
- 在java的代码中
select * from user where name like #{u_name};
name="%value%"
- 在sql 中写死
select * from user where id like "%"#{u_name}"%";
- 在java的代码中
-
配置解析
-
environments
配置不同的连接数据库的配置
-
properties
配置外部属性
database.properties
-
标签顺序很重要
-
别名
-
xml
- typeAlias
- package
<typeAliases> <!-- <typeAlias type="com.itCast.domain.User" alias="user"/>--> <package name="com.itCast.domain"/> </typeAliases>
-
注解 xml : package
- 可以通过注解自定义名字
@Alias("user01")
- 可以通过注解自定义名字
-
-
映射
-
方式一
<mappers> <mapper resource="com/itCast/dao/UserMapper.xml"/> </mappers>
-
方式二
<mappers> <mapper class="com.itCast.dao.UserMapper"/> </mappers>
- 方式二的注意点
- 接口名字必须和xml名字一致
- 并且接口和xml映射必须在同包之下
- 方式二的注意点
-
方式三
<package name="com.itCast.domain"/>
- 要求和方式二一致
-
-
如何解决字段名和类属性不一致
-
修改Sql
-
resultMap
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itCast.dao.UserMapper"> <!-- resultMap=id --> <resultMap id="userMap" type="user"> <!-- column: 列 数据库 property 属性 类属性 --> <result column="id" property="uId"/> <result column="u_name" property="uName"/> <result column="u_pass" property="uPass"/> </resultMap> <!-- 按照ID查询--> <select id="findUserById" resultMap="userMap" parameterType="int"> select * from user where id = #{id}; </select> </mapper>
- 字段一致不需要写
<result column="id" property="uId"/>
- 字段一致不需要写
-
-
-
日志
-
常用的 LOG4J
-
配置文件来灵活配置日志输出
-
LOG4J使用
-
导入依赖
<!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
加入
log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码 log4j.rootLogger=DEBUG,console,file #控制台输出的相关设置 log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%c]-%m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/kexing.log log4j.appender.file.MaxFileSize=10mb log4j.appender.file.Threshold=DEBUG log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n #日志输出级别 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
-
private static Logger logger =Logger.getLogger(MapperTest.class); logger.info("info:信息"); SqlSession session = mybatisUtils.getSqlSession(); UserMapper mapper = session.getMapper(UserMapper.class); List<User> users = mapper.findUserById(1); for (User user : users) { logger.debug(user); } logger.error("error");
-
-
-
分页查询
-
xml
<!-- 分页查询--> <select id="findUserLimit" parameterType="map" resultMap="userMap"> select * from user limit #{startIndex},#{pageSize}; </select>
-
test
@Test public void findUserLimitTest(){ SqlSession session = mybatisUtils.getSqlSession(); UserMapper mapper = session.getMapper(UserMapper.class); Map<String, Integer> map = new HashMap<>(); map.put("startIndex",1); map.put("pageSize",4); List<User> users = mapper.findUserLimit(map); for (User user : users) { System.out.println(user); } session.close(); }
-
-
注解
- 注意
${}
#{}
获取值的方式第二种更安全,前者容易sql注入
- 注意
-
lombok 简化Javabean的书写
-
idea 下载
plugins
-
maven 坐标
-
注解使用
@ToString @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode @Getter @Setter @Data
-
三,多表关系和动态SQL
-
动态SQL
-
接口
List<User> findUserByCondition(User user);
-
XML
<!-- 条件查询--> <select id="findUserByCondition" parameterType="user" resultMap="userMap"> select * from user <where> <if test="uId!=0" > and id = #{uId} </if> <if test="uName!=null"> and u_name = #{uName} </if> <if test="uPass!=null"> and u_pass = #{uPass} </if> </where> </select>
<!-- 根据集合查询--> <select id="findUserByIds" parameterType="list" resultMap="userMap"> <include refid="findUser"/> <where> <foreach collection="list" open="id in (" close=")" separator="," item="id"> #{id} </foreach> </where> </select>
<!-- sql 抽取--> <sql id="findUser"> select * from user </sql>
-
测试
//条件查询 @Test public void findUserByConditionTest(){ SqlSession session = mybatisUtils.getSqlSession(); UserMapper mapper = session.getMapper(UserMapper.class); List<User> user = mapper.findUserByCondition(new User(1, "user1", "user1")); for (User user1 : user) { System.out.println(user1); } session.close();
-
-
多表查询
-
一对多
-
sql 语句
select u.id uid,u.u_name uname,a.id aid,a.money amoney from user u,account a where u.id = a.u_id;
-
map
<resultMap id="userAccount" type="java.util.Map"> <result property="aid" column="aid"/> <result property="uname" column="uname"/> <result property="amoney" column="amoney"/> </resultMap>
List<HashMap<Object,Object>> findUserAccount();
-
-
多对一
-
sql
select u.id uid,u.u_name uname,a.id aid,a.money amoney from user u left join account a on u.id = a.u_id;
-
结果集
<resultMap id="AccountUser" type="userA"> <id property="id" column="uid"/> <result property="u_name" column="uname"/> <!-- javaTyp指定类型 ofType 集合泛型 private int id; private int u_id; private int money; --> <collection property="account" ofType="account"> <id property="id" column="aid"/> <result property="money" column="amoney"/> </collection> </resultMap>
-
-
四,核心配置文件
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HUAvrhJQ-1636367705235)(D:\ycdl\JavaNote\笔记\img\mybatis1.jpg)]
-
自定义类型转换器
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ibxb205o-1636367705238)(C:\Users\2775371841\AppData\Roaming\Typora\typora-user-images\image-20210415163845457.png)]
-
代码
public class DateTypeHandler extends BaseTypeHandler<Date> { //java 类型转换成数据库需要的类型 @Override public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException { long time = parameter.getTime(); ps.setLong(i,time); } //数据库类型转换成java需要的类型 @Override public Date getNullableResult(ResultSet rs, String columnName) throws SQLException { long rsLong = rs.getLong(columnName); Date date = new Date(rsLong); return date; } //数据库类型转换成java需要的类型 @Override public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException { long rsLong = rs.getLong(columnIndex); Date date = new Date(rsLong); return date; } //数据库类型转换成java需要的类型 @Override public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { long rsLong = cs.getLong(columnIndex); Date date = new Date(rsLong); return date; } }
<typeHandlers> <typeHandler handler="com.utils.DateTypeHandler"/> </typeHandlers>
-
plugains
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LiRj7yM2-1636367705239)(D:\ycdl\JavaNote\笔记\img\mybatis3.jpg)]
-
导入依赖
-
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.6</version> </dependency>
<!-- https://mvnrepository.com/artifact/com.github.jsqlparser/jsqlparser --> <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>1.4</version> </dependency>
-
-
在主配置文件上配置
-
<plugins> <plugin interceptor="com.github.pagehelper.PageHelper"> <!-- 属性是数据库不同语言不同--> <property name="dialect" value="mysql"/> </plugin> </plugins>
-
-
test
-
//第二种方式 @Test public void getUserListTest2(){ SqlSession session = mybatisUtils.getSqlSession(); // System.out.println(session); UserMapper mapper = session.getMapper(UserMapper.class); PageHelper.startPage(1,3); List<User> list = mapper.getUserList(); for (User user : list) { System.out.println(user); } }
-
-
特别注意
- sql不能加
;
- 在查询所有时才管用
- sql不能加
五, 延迟加载概念,和怎么配置延迟加载,以及他的原理
- 延迟加载的概念
mybatis的延迟加载就是按需查询,在需要的时候进行查询 (分步查询,按需查询)
当然 Hibernate也是支持的
这样做可以完成功能,但是我们只是需要显示图书类型,点击的时候才显示该类型的图书,如果能做到开始只查询类型,点击类型的时候再查询该类型的图书,就不需要进行两表联查了,可以提高查询的效率,也比较节省内存,这就是延迟加载。
- 哪些方面支持
mybatis仅仅支持association(一对一) collection(一对多) 的延迟加载
- 如何设置使用
<mapper namespace="cn.xh.dao.UserDao">
<select id="findCategoryWithLazingload" resultMap="categoryMap">
select * from category
</select>
<resultMap id="categoryMap" type="cn.xh.pojo.Category">
<id column="cid" property="cid"></id>
<result column="cname" property="cname"></result>
<collection property="books" column="cid" select="findBookWithLazy"></collection>
</resultMap>
<select id="findBookWithLazy" parameterType="int" resultType="cn.xh.pojo.Book">
select * from book where cid = #{cid}
</select>
</mapper>
<settings>
<!--启动延迟加载 默认为false-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--按需加载,默认为true-->
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
六,缓存
-
什么是缓存
- 存在内存中的临时数据
- 将用户经常查的数据放进缓存,降低访问数据库的次数,提高性能
-
mybatis 缓存
-
方便的定制和配置缓存
-
定于了两级缓存
-
默认开启一级缓存,
SqlSession
级别(本地缓存)-
一次会话 ,close() 后关闭
-
一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方
法时,就会清空一级缓存。防止后续查询发生脏读(脏读:查询到过期的数据) -
特别注意 一个mapper中sqlid是方法全路径 ,所以同一个mapper不能共享需要二级缓存
-
Mybatis内部存储缓存使用一个HashMap缓存数据,key为hashCode+sqlId+Sql语句。value为从查询
出来映射生成的java对象。
一级缓存的范围有SESSION和STATEMENT两种,默认是SESSION,如果不想使用一级缓存,可以把一
级缓存的范围指定为STATEMENT,这样每次执行完一个Mapper中的语句后都会将一级缓存清除(禁用
一级缓存)。
-
-
二级缓存需要手动开启 多个sqlsession(相同的namespace)
- 通过
Cache
接口来定义二级缓存
- 通过
-
-
原则
- 最近最少使用
- 先进先出
-
-
一级缓存和二级缓存
-
一级缓存失效
select
语句执行结果会被缓存- 数据库写入时缓存失效
- 最近最少使用算法
- 不定时刷新缓存
- 调用的对象不共享可以安全的被修改,互相不受影响
-
二级缓存
-
开启
-
在主配置文件中写入
-
<setting name="cacheEnabled" value="true" />
-
-
在Mapper.xml文件中开启
-
<cache/>
-
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
-
-
-
生效
- 在Mapper.xml全局生效
- 在关闭会话时一级缓存会保存在二级缓存
- Mapper.xml 的数据会保存在自己当中
-
顺序
- 先看二级缓存
- 再看一级缓存
- 然后找不到,看数据库
-
-