1. Mybatis核心的配置文件
<?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 resource="db.properties" />
<settings>
<!--默认的日志工厂 stdout_logging-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--是否开启驼峰命名自动映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--全局开启缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
<typeAliases>
<!--起别名的三种方式
1. typeAliases指定实体类 pojo
2. typeAliases指定实体类的包名
3. 在实体类上使用@Alias("author")注解
-->
<package name="com.mingde.pojo"/>
</typeAliases>
<environments default="development"><!--环境配置 SqlSessionFactory实例只能选择一个环境-->
<environment id="development">
<transactionManager type="JDBC" /><!--事务管理器 type="[JDBC|MANAGED]")-->
<dataSource type="POOLED">
<!--数据源-->
<property name="driver" value="${driver}" /><!--三种内建的数据源类型 type="[UNPOOLED|POOLED|JNDI]-->
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<!--3种映射器
1. 推荐使用的resource
2. class 注意 1. 接口和他的Mapper配置文件相同 2. 接口和他的Mapper配置文件必须在同一个包下
3. packet 扫描包进行注解绑定 注意点和第二种映射器相同。
-->
<mappers>
<mapper class="com.mingde.mapper.UserMapper"/>
</mappers>
</configuration>
1. environments
-
配置Mybatis的多套运行环境,将SQL映射到多个不同的数据上,必须指定一个为默认的运行环境。
-
environment位environments的子标签。
-
transactionManager的二种事务管理器
- JDBC:直接使用了JDBC的提交和回滚设施,它依赖从数据源获得连接来管理事务的作用域;
- MANAGED:这个配置几乎没有做什么。
-
dataSource三种的数据源类型
-
UNPOOLED: 这个数据源的实现会每次请求时打开和关闭连接。
-
POOLED:实现利用了“池”的概念将JDBC连接对象组织起来,避免了创建新的连接实例时的所必须的初始化和认证时间。
-
JNDI:为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的数据源引用。
-
2. 映射器(mappers)
- 使用相对域类路径的资源引用
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml" />
<mappers>
- 使用映射器接口实现类的完全限定类名
<mappers>
<mapper class="org.mybatis.builder/AuthorMapper" />
</mappers>
-
使用完全限定资源定位符(URL) 不推荐
-
将包内的映射器接口实现全部注册为映射器
<mappers>
<package name="org.mybatis.builder" />
</mappers>
3. 起别名的三种方式
- typeAliases标签里中的typeAlias指定实体类pojo
- typeAliases标签里中的package指定实体类的包名
- 在实体上使用注解@Alias(“xxx”)
2. 作用域(Scope)和生命周期
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* 1. SqlSessionFactoryBuilder 这个类可以被实例化、使用和丢弃,一旦创建SqlSessionFactory就不需要它了,最佳作用域是方法作用域(局部方法变量)
* 2. SqlSessionFactory 一旦创建任何时候都存在,最佳作用域应用作用域
* 3. SqlSession 线程不安全不能共享 最佳作用域请求和方法作用域
* */
public class MybatisConfig {
static SqlSessionFactory build;
static {
try {
String resource = "mybatis-config.xml";
InputStream resourceAsStream = Resources.getResourceAsStream(resource);
build = new SqlSessionFactoryBuilder().build(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
return build.openSession(true);
}
}
1. SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
2. SqlSessionFactory
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
3. SqlSession
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。
3. 三种分页方式
#语法
SELECT * FROM table LIMIT stratIndex,pageSize
SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15
#为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:
SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.
#如果只给定一个参数,它表示返回最大的记录行数目:
SELECT * FROM table LIMIT 5; //检索前 5 个记录行
#换句话说,LIMIT n 等价于 LIMIT 0,n。
1. Mybatis中的xml文件拼接SQL语句
<select id="selectUser" parameterType="map" resultType="user">
select * from user limit #{startIndex},#{pageSize}
</select>
2.RowBounds分页
查找出所有信息再进行分页。
@Test
public void testUserByRowBounds() {
SqlSession session = MybatisUtils.getSession();
int currentPage = 2; //第几页
int pageSize = 2; //每页显示几个
RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize);
//通过session.**方法进行传递rowBounds,[此种方式现在已经不推荐使用了]
List<User> users = session.selectList("com.kuang.mapper.UserMapper.getUserByRowBounds", null, rowBounds);
for (User user: users){
System.out.println(user);
}
session.close();
}
3. PageHelper
官方文档:https://pagehelper.github.io/
4. 关联
- 关联的嵌套Select查询
<resultMap id="blogResult" type="Blog">
<association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectAuthor" resultType="Author">
SELECT * FROM AUTHOR WHERE ID = #{id}
</select>
- 关联嵌套结果查询
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id" />
<result property="title" column="blog_title"/>
<association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
</resultMap>
<resultMap id="authorResult" type="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="password" column="author_password"/>
<result property="email" column="author_email"/>
<result property="bio" column="author_bio"/>
</resultMap>
5. 集合
- 集合的嵌套 Select 查询
<resultMap id="blogResult" type="Blog">
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectPostsForBlog" resultType="Post">
SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>
- 集合的嵌套结果映射
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id" />
<result property="title" column="blog_title"/>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
</resultMap>
6. 动态SQL
- if:提供了可选的查找文本功能;
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
- choose、when、otherwise相当于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>
- trim:可以用来实现where和set元素的功能。prefixOverrides 属性会忽略通过管道符分隔的文本序列;
- where:元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
- set:set 元素可以用于动态包含需要更新的列;
- foreach:对集合进行遍历
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
7. 缓存
1、什么是缓存 [ Cache ]?
- 存在内存中的临时数据。
- 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
2、为什么使用缓存?
- 减少和数据库的交互次数,减少系统开销,提高系统效率。
3、什么样的数据能使用缓存?
- 经常查询并且不经常改变的数据。
1. 一级缓存
一级缓存也叫本地缓存:
- 与数据库同一次会话期间查询到的数据会放在本地缓存中。
- 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
2. 二级缓存
-
二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
-
基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
-
工作机制
-
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
- 新的会话查询信息,就可以从二级缓存中获取内容;
- 不同的mapper查出的数据会放在自己对应的缓存(map)中;
https://mp.weixin.qq.com/mp/homepage?__biz=Mzg2NTAzMTExNg==&hid=3&sn=456dc4d66f0726730757e319ffdaa23e&scene=18#wechat_redirect
https://mybatis.org/mybatis-3/