mybatis学习笔记

Mybatis

官网:https://mybatis.org/mybatis-3/index.html

下载地址:https://github.com/mybatis/mybatis-3/releases

依赖:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.2</version>
</dependency>

一、第一个Mybatis程序

1.搭建环境

搭建数据库

CREATE DATABASE `mybatis`;
USE `mybatis`
CREATE TABLE `user`(
	`id` INT(20) NOT NULL,
	`name` VARCHAR(30) DEFAULT NULL,
	`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`pwd`)VALUES
(1,"张三","123456"),
(2,"李四","123456"),
(3,"王五","123456")

新建项目

  1. 普通maven项目
  2. 删除src目录
  3. 导入依赖 数据库,mybatis junit
<!--        数据库连接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
<!--        mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
<!--        junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>

2.创建一个模块

  • 编写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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;amp;characterEncoding=utf8&amp;amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
  • 编写mybatis工具类
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            String resource = "org/mybatis/example/mybatis-config.xml";
            InputStream inputStream = inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

3.编写代码

  • 实体类
  • Dao接口

二、CRUD

流程:

  • 编写接口
public interface UserDao {
//    查询用户信息
    List<User> getUser();
//    按id查询用户信息
    User getUser1(int id);
//    增加用户信息
    int addUser(User user);
//    修改用户信息
    int updateUser(User user);
//    删除用户信息
    int delUser(int id);
}
  • 编写对应的mapper中的sql语句
<select id="getUser" resultType="com.study.pojo.User">
    select * from user
</select>

<select id="getUser1" resultType="com.study.pojo.User" parameterType="int">
    select * from user where id=#{id}
</select>

<insert id="addUser" parameterType="com.study.pojo.User">
    insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>

<update id="updateUser" parameterType="com.study.pojo.User">
    update user set name=#{name},pwd=#{pwd} where id=#{id}
</update>

<delete id="delUser" parameterType="int">
    delete from user where id=#{id}
</delete>
  • 测试

注意点:增删改 需要提交事务

万能的Map

使用Map传递参数:方便,灵活

int addUser1(Map<String,Object> map);
<insert id="addUser1" parameterType="map">
insert into user (id,name ,pwd) values (#{id},#{name},#{pwd})
</insert>
public void addUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("id",6);
map.put("name","666");
map.put("pwd","666666");
mapper.addUser1(map);  
sqlSession.commit(); 
sqlSession.close();}

模糊查询

1.在传参时候写

2.在sql拼接中使用通配符

三、配置解析

1.核心配置文件

2.环境配置(environments)

  • <transactionManager type="JDBC"/>  默认为jdbc
    
  • <dataSource type="POOLED"> 数据源默认是池
    

3.属性(properties)

  • 编写db.properties
driver = com.mysql.jdbc.Driverurl = jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=falseusername = rootpassword = 123456
  • 在mybatis-config.xml中引入配置文件
<!--核心配置文件-->
<configuration>
	<!--    引入外部属性-->
	<properties resource="db.properties" />
	<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="com/study/dao/UserDaoMapper.xml"></mapper>   
</mappers>
</configuration>

4.类型别名(typeAliases)

  • 给实体类起别名
<typeAliases>    <typeAlias type="com.study.pojo.User" alias="user"/></typeAliases>
  • 扫描包
<typeAliases>    <package name="com.study.pojo"/></typeAliases>

在实体类比较少时,使用第一种方式。

实体类十分多,使用第二种。

第一种可以DIY别名,第二种不行,非要改在实体上增加注解

@Alias("hello")public class User {   ············    }

5.设置(settings)

  • mapUnderscoreToCamelCase true
  • 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。

6.映射器(mappers)

  • 注册绑定我们的Mapper文件

方式一、resource

<mappers>    <mapper resource="com/study/dao/UserDaoMapper.xml"></mapper></mappers>

方式二、class

<mapper class="com.study.dao.UserDaoMapper"/>
  • 注意点:
  • 接口和他的Mapper文件必须同名
  • 接口和他的Mapper文件必须在同一个包下

方式三、package

<package name="com.study.dao"/>
  • 注意点:
  • 接口和他的Mapper文件必须同名
  • 接口和他的Mapper文件必须在同一个包下

7.生命周期和作用域

四、解决属性名和字段名不一致问题

1.暴力解决

  • 起别名
<select id="getUser1" resultType="user" parameterType="int">
	select id,name,pwd as password from user where id=#{id}
</select>

2.使用resultmap解决

<resultMap id="userMap" type="user">
	<result column="pwd" property="password"/>
</resultMap>
<!--查询语句-->
<select id="getUser1" resultMap="userMap" parameterType="int"> 
	select * from user where id=#{id}
</select>

五、日志

1.日志工厂 logImpl

数据库操作出现异常,需要排错。日志就是最好的助手。

  • SLF4J
  • LOG4J 【掌握】
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING 【掌握】
  • NO_LOGGING

在mybatis文件中配置我们的日志

<!--    日志输出--> 
<settings>      
	<setting name="logImpl" value="STDOUT_LOGGING"/>  
</settings>

1.STDOUT_LOGGING 【掌握】标准日志输出

2.LOG4J

  1. 导包
<!--        LOG4J-->
<dependency>  
	<groupId>log4j</groupId>   
	<artifactId>log4j</artifactId>  
	<version>1.2.17</version>
</dependency>
  1. 写配置文件

log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码log4j.rootLogger=DEBUG,console,file#控制台输出的相关设置log4j.appender.console = org.apache.log4j.ConsoleAppenderlog4j.appender.console.Target = System.outlog4j.appender.console.Threshold=DEBUGlog4j.appender.console.layout = org.apache.log4j.PatternLayoutlog4j.appender.console.layout.ConversionPattern=[%c]-%m%n#文件输出的相关设置log4j.appender.file = org.apache.log4j.RollingFileAppenderlog4j.appender.file.File=./log/kuang.loglog4j.appender.file.MaxFileSize=10mblog4j.appender.file.Threshold=DEBUGlog4j.appender.file.layout=org.apache.log4j.PatternLayoutlog4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n#日志输出级别log4j.logger.org.mybatis=DEBUGlog4j.logger.java.sql=DEBUGlog4j.logger.java.sql.Statement=DEBUGlog4j.logger.java.sql.ResultSet=DEBUGlog4j.logger.java.sql.PreparedStatement=DEBUG
  1. <!--    日志输出-->    <settings>        <setting name="logImpl" value="LOG4J"/>    </settings>
    
  • 简单使用
  1. 导入包
import org.apache.log4j.Logger;
  1. 日志对象
static Logger logger = Logger.getLogger(UserDaoTest.class);
logger.info("发送错误");logger.debug("发送错误");logger.error("发送错误");

六、分页

语法:select * from user limit startIndex,pageSize

1.使用limit

1.编写接口

//    分页查询List<User> getUserByLimit(Map<String,Integer> map);

2.Mapper.xml

<!--分页查询-->
<select id="getUserByLimit" parameterType="map" resultMap="userMap">
	select * from user limit #{startIndex},#{pageSize}
</select>

3.测试

@Testpublic void getUserByLimitTest(){
	SqlSession sqlSession = MybatisUtils.getSqlSession();
	UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class);
	HashMap<String, Integer> map = new HashMap<>();
	map.put("startIndex",0);
	map.put("pageSize",3);
	List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
	System.out.println(user); 
}
	sqlSession.close();
}

2.RowBounds

  • 不在使用sql 分页
  1. 编写接口
//    分页查询    List<User> getUserByRowBounds();
  1. Mapper.xml
<!--分页查询-->
<select id="getUserByRowBounds" resultMap="userMap"> 
	select * from user
	</select>
  1. 测试
public void getUserByRowBounds(){
	RowBounds rowBounds = new RowBounds(0,3);
	SqlSession sqlSession = MybatisUtils.getSqlSession();
	List<User> userList = sqlSession.selectList("com.study.dao.UserDaoMapper.getUserByRowBounds", null, rowBounds);
	for (User user : userList) {
		System.out.println(user);  
	}
	sqlSession.close();
}

3.分页插件

  • PageHelper 了解

七、使用注解开发

1.面向接口编程

  • 解耦

2.使用注解开发

  • 底层实现机制:反射
  • 底层:动态代理
  1. 注解直接在接口上实现
//    查询用户信息    @Select("select * from user")    List<User> getUser();
  1. 需要再核心配置文件中绑定接口
<mappers>    <mapper class="com.study.dao.UserDaoMapper"/></mappers>
  1. 测试
public void getUser(){
	SqlSession sqlSession = MybatisUtils.getSqlSession();
	UserDaoMapper mapper =  sqlSession.getMapper(UserDaoMapper.class);
	List<User> user = mapper.getUser();
	for (User user1 : user) {  
		System.out.println(user1);
	}   
	sqlSession.close();
}

3.CRUD

  1. 工具类创建时候实现自动提交事务
sqlSessionFactory.openSession(true);
  1. 编写接口,增加注解
//    查询用户信息    
@Select("select * from user")
List<User> getUser();
//    按id查询用户信息   
@Select("select * from user where id=#{uid}")  
User getUser1(@Param("uid") int id);
//    增加用户信息  
@Insert("insert into user(id,name,pwd) value(#{id},#{name},#{pwd})")  
int addUser(User user);
@Insert("insert into user(id,name,pwd) value(#{uid},#{uname},#{upwd})")  
int addUser1(Map<String,Object> map);
//    修改用户信息   
@Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")  
int updateUser(User user);
//    删除用户信息   
@Delete("delete from user where id=#{id}") 
int delUser(int id);
  1. 测试

【注意:我们必须将接口注册绑定到 核心配置文件中】

4.@Param注解

  • 基本类型参数或者String类型,需要加
  • 引用类型不需要
  • 如只有一个基本类型的话,忽略,
  • 我们在SQl中引用的就是我们这里的@param

八、Lombok

使用步骤:

  1. 在IDEA中安装Lombok插件
  2. 项目中导入lombokjar包
<dependency>
	<groupId>org.projectlombok</groupId> 
	<artifactId>lombok</artifactId>   
	<version>1.18.10</version>
</dependency>
  1. 在实体类上面注解
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@RequiredArgsConstructor and @NoArgsConstructor@Log,
@Log4j,
@Log4j2,
@Slf4j,
@XSlf4j,
@CommonsLog,
@JBossLog,
@Flogger,
@CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
@Data 无参构造 get set equals tostring hashCode
@AllArgsConstructor 有参构造
@NoArgsConstructor  无参构造
@AllArgsConstructor
@NoArgsConstructor
public class User { 
	private int id; 
	private String name; 
	private String pwd;
}

九、多对一处理

环境搭建

  1. 导入lombok依赖
  2. 编写实体类
  3. 编写Mapper接口
  4. 编写对应的Mapper.xml文件
  5. 在核心配置文件中注册
  6. 测试

1.按照查询嵌套处理

<resultMap id="studentTeacher" type="student"> 
	<result property="id" column="id"/>  
	<result property="name" column="name"/>
<!--复杂的属性我们需要单独处理-->  
	<association property="teacher" javaType="Teacher" column="tid" select="getTeacher" /></resultMap> 
<select id="getStudent" resultMap="studentTeacher">   
	select * from student   
</select>
<select id="getTeacher" resultType="Teacher">  
	select * from teacher where id=#{tid}  
</select>

2.按照结果嵌套处理

<resultMap id="studentTeacher1" type="student">  
	<result property="id" column="sid"/>  
	<result property="name" column="sname"/>  
	<association property="teacher" javaType="Teacher">   
		<result property="id" column="tid"/>   
		<result property="name" column="tname"/> 
	</association>
</resultMap>
<select id="getStudent1" resultMap="studentTeacher1">  
	select s.id sid,s.name sname,t.id tid,t.name tname from student s,teacher t where s.tid=t.id
</select>

十、一对多处理

1.按照结果处理

<!--    根据结果集查询-->  
<resultMap id="TeacherStudent" type="Teacher">    
	<result property="id" column="tid"/>  
	<result property="name" column="tname"/>   
	<collection property="students" ofType="student">  
		<result property="id" column="sid"/>     
		<result property="name" column="sname"/>    
	</collection>   
</resultMap>  
<select id="getTeacher" resultMap="TeacherStudent">   
	select t.id tid,t.name tname,s.id sid,s.name sname from student s,teacher t where s.tid=t.id and t.id=#{tid}   
</select>

2.按照查询嵌套处理

<!--    按照查询嵌套处理-->
<resultMap id="TeacherStudent1" type="Teacher"> 
	//column="id" 是传参作用  
	<collection property="students" javaType="ArrayList" ofType="student" select="getStudent" column="id"/>
</resultMap>  
<select id="getTeacher1" resultMap="TeacherStudent1"> 
	select * from teacher where id=#{tid}</select><select id="getStudent" resultType="student">   select * from student where tid=#{tid}
</select>

十一、动态SQL

搭建环境

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT &#39;博客id&#39;,
`title` VARCHAR(100) NOT NULL COMMENT &#39;博客标题&#39;,
`author` VARCHAR(30) NOT NULL COMMENT &#39;博客作者&#39;,
`create_time` DATETIME NOT NULL COMMENT &#39;创建时间&#39;,`
views` INT(30) NOT NULL COMMENT &#39;浏览量&#39;
)ENGINE=INNODB DEFAULT CHARSET=utf8

IF

<select id="getBlogIF" parameterType="map" resultType="Blog"> 
	select * from blog where 1=1   
	<if test="title != null">     
		and title = #{title}   
	</if>   
	<if test="author != null"> 
		and author = #{author}  
	</if>
</select>

Where

  • where标签会自动去除 and
<select id="queryBlogChoose" resultType="Blog">
	select * from blog   
	<where>    
		<if test="title != null">       
			title = #{title}    
		</if>      
		<if test="author != null">   
			and author = #{author}  
		</if>  
	</where>
</select>

choose、when、otherwise

  • 相对于是 switch
  • 按顺序 只要有成立的 就返回
  • 如果 都不成立就走 othorwise中的
<select id="queryBlogChoose" resultType="Blog"> 
	select * from blog   
	<where>      
		<choose>     
			<when test="title != null">    
				title = #{title}    
			</when>       
			<when test="author != null">    
				and author = #{author}   
			</when>       
			<otherwise>   
				views = #{views}   
			</otherwise>   
		</choose>  
	</where>
</select>

set

<update id="updateBlog" parameterType="map">  
	update blog  
	<set>   
		<if test="title != null">  
			title = #{title},    
		</if>    
		<if test="author != null">   
			author = #{author}    
		</if>  
	</set>   
	where id = #{id}
</update>

trim

  • 使用trim 实现set标签
<update id="updateBlog" parameterType="map">
	update blog  
	<trim prefix="set" suffixOverrides=",">   
		<if test="title != null">   
			title = #{title},   
		</if>      
		<if test="author != null">     
			author = #{author}   
		</if>  
	</trim> 
	where id = #{id}
</update>
  • 使用trim 实现where标签
<select id="queryBlogChoose" resultType="Blog">  
	select * from blog 
	<trim prefix="where" prefixOverrides="and | or">  
		<choose>     
			<when test="title != null">  
				title = #{title}     
			</when>       
			<when test="author != null">    
				and author = #{author}  
			</when>     
			<otherwise>     
				views = #{views}   
			</otherwise>  
		</choose> 
	</trim>
</select>

SQL片段

  • 有的时候,我们可能需要将一些功能的部分抽取出来,方便复用

使用方法:

  • 使用sql标签
  • 使用include标签
<sql id="if-title-author"> 
	<if test="title != null">   
	title = #{title},  
	</if>   
	<if test="author != null">  
	author = #{author}   
	</if>
</sql>
<update id="updateBlog" parameterType="map">  
	update blog 
	<trim prefix="set" suffixOverrides=",">
		<include refid="if-title-author"></include>  
	</trim>  
	where id = #{id}
</update>

注意事项:

  • 不要存在where标签

Foreach

需求实现:

select * from blog where 1=1 and (id=1 or id=2 or id=3)
<!--select * from blog where 1=1 and (id=1 or id=2 or id=3)-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">   
	select * from blog  
	<where>   
	<foreach collection="ids" item="id" open="and (" close=")" separator="or">      
		id=#{id} 
	</foreach>
	</where>
</select>
  • 注意这里collection="ids" 传的参数是 集合的名字 不需要加#{}

总结建议

  • 先在MySql中写出完整的语句,再去修改成为我们的动态sql即可

十二、缓存

一级缓存SqlSession

  • 默认是开启的,无法关闭
  • 只在一次SqlSession中有效,也就是在得到连接-关闭连接有效
  • update insert delete操作会清除缓存
  • SqlSession.cleanCache()手动清除缓存

二级缓存nameSpace

  • 只要开启了二级缓存,在同一个Mapper下有效
  • 所有数据都会先放在一级缓存中
  • 只有当会话提交,或关闭的时候,才会提交到二级缓存

使用方法:

  1. 显示开启二级缓存
<!--        开启二级缓存-->        <setting name="cacheEnabled" value="true"/>
  1. 在 Mapper.xml中写入
<cache/>

​ 也可以自定义一些参数

<cache  eviction="FIFO"			  flushInterval="60000"  size="512"  readOnly="true"/>
  1. 测试

问题:实体类需要序列化,继承 Serializable

public class Blog implements Serializable 

缓存原理

  1. 先查二级缓存
  2. 在查一级缓存
  3. 都没有再去数据库查找

自定义缓存-ehcache

  1. 导如jar包
<dependency>    <groupId>org.mybatis.caches</groupId>    <artifactId>mybatis-ehcache</artifactId>    <version>1.1.0</version></dependency>
原文地址:https://www.cnblogs.com/20183544-wangzhengshuai/p/15237061.html