简介
1、持久层框架
2、maven仓库获取
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
构建mybatis项目
1、编写mybatis 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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
2、编写mybatis工具类
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
InputStream inputStream = null;
try {
String resource = "mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
3、编写dao层接口
public interface UserMapper {
public List<User> getUserList();
}
4、编写mapper.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">
<mapper namespace="com.tang.dao.UserMapper">
<select id="getUserList" resultType="com.tang.pojo.User">
select * from user
</select>
</mapper>
5、测试类
public class UserDaoTest {
@Test
public void test(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
}
maven资源过滤
<!-- 资源过滤-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
CRUD操作
parameterType:参数类型
resultType:返回类型
查询用户通过id:
<select id="getUserById" parameterType="int" resultType="com.tang.pojo.User"> select * from user where id=#{id} </select>
增加用户
注意:增删改需要提交事务
<insert id="addUser" parameterType="com.tang.pojo.User"> insert into user(id,name,pwd) values(#{id},#{name},#{pwd}) </insert>
public void addUser(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(new User(9,"hahha","123"));
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
配置解析
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
1、environments(环境配置)
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
注:1、在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")
2、有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
3、MyBatis默认使用事务管理器JDBC 连接池POOLED
2、properties(属性)
创建db.properties文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username=root
password=root
在mybatis-config.xml中引入properties文件
<configuration>
<properties resource="db.properties"/>
....
</configuration>
当两个文件同一字段,优先使用外部配置文件。
3、类型别名(typeAliases)
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
....
</typeAliases>
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值
@Alias("author")
public class Author {
...
}
4、设置(settings)
设置名 描述 有效值
cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 true | false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 true | false
logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 未设
5、映射器(mappers)
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
注意:1、使用此方法,接口必须和他的mapper配置文件名相同
2、接口和他的mapper配置文件必须在同一包下
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
注意:1、使用此方法,接口必须和他的mapper配置文件名相同
2、接口和他的mapper配置文件必须在同一包下
### 6、作用域(Scope)和生命周期 ###
SqlSessionFactoryBuilder:这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory:SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
SqlSession:SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。
结果映射resultMap
resultMap 元素是 MyBatis 中最重要最强大的元素。
然后在引用它的语句中设置 resultMap 属性就行了
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
日志
作用:出现异常排错
以前:sout debug
SLF4J
LOG4J 【掌握】
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING 【掌握】
NO_LOGGING
标准日志STDOUT_LOGGING 输出
<settings>
<setting name="logImpl" value="STDOUT_LOGGING "/>
</settings>
LOG4J
1、导包
2、创建log4j.properties配置文件
设置
log4j.rootLogger = debug,stdout,D,E
输出信息到控制抬
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
输出DEBUG 级别以上的日志到=E://logs/error.log
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
输出ERROR 级别以上的日志到=E://logs/error.log
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
使用注解开发
@Param()
基本类型的参数需要加上
引用类型不用加
我们在sql中的引用就是@Param()中设定的属性名
多对一查询
按照查询嵌套处理
<!--思路:
1、查询所有学生的信息
2、根据查询出来学生信息的tid,寻找对应的老师-->
<select id="getStudent" resultType="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id=#{id}
</select>
</mapper>
按照结果嵌套处理
<!-- 按照结果嵌套处理-->
<select id="getStudent2" resultType="StudentTeacher2">
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
一对多查询
例如:一个老师有多个学生
按照结果嵌套查询
<!-- 按照结果嵌套处理-->
<select id="getTeacher" resultType="StudentTeacher">
select s.id sid,s.name sname,t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher" type="teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!-- 复杂的属性,我们需要单独处理 对象association 集合:collection
javaType指定属性的类型
ofType指定集合中,泛型的类型-->
<collection property="Students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
按照查询嵌套处理
<!-- 按照查询嵌套处理-->
<select id="getTeacher" resultType="StudentTeacher2">
select * from teacher where id = #{tid}
</select>
<resultMap id="StudentTeacher2" type="Teacher">
<collection property="Students" column="id" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from student where tid=#{tid}
</select>
小结:
1、关联 多对一 association
2、集合 一对多 collection
3、javaType & ofType
javatype:指定实体类属性类型
ofType:指定映射到list或者集合中的泛型类型
动态sql
if
这条语句提供了可选的查找文本功能。如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
where
where 元素只会在子元素有返回内容的情况下才插入 “WHERE” 子句。
若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
set
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
和 where 元素等价的自定义 trim 元素为:
...
与 set 元素等价的自定义 trim 元素:
...
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历
它允许你指定一个集合(list)
index 是当前迭代的序号
item 的值是本次迭代获取到的元素
缓存
默认情况下,只启用了本地的会话缓存(一级缓存),它仅仅对一个会话中的数据进行缓存。
要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
基本上就是这样。这个简单语句的效果如下:
映射语句文件中的所有 select 语句的结果将会被缓存。
映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
缓存不会定时进行刷新(也就是说,没有刷新间隔)。
二级缓存
1、开启默认缓存(一般默认开启,单独写出来,起提示作用)
2、在当前mapper.xml中,添加
小结:
1、只要开启了二级缓存,在同一个mapper下生效,二级缓存只能针对一个namespace有效。。
2、所有数据先放入一级缓存中,当一级缓存关闭或提交时,自动放入二级缓存。
原理
第一次查询先看二级缓存里面有没有,在看一级缓存里面,没有就查询。
资料来源:B站秦疆老师(遇见狂神说)
https://space.bilibili.com/95256449