mybatis详解
mybatis学习最好是看官方文档学习
还不够详细,标题党了属于是,对不起!!!
mybatis官方文档
该网站难打开,可以多试试或是用流量打开
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
接下的项目是由maven来管理
maven下载与配置
一、入门
1)导包
pom.xml 中操作
- 连接数据库 mysql-connector-java.jar
- 使用mybatis mybatis.jar
- 测试 junit.jar
- 快速实现get&set函数的插件 lombok.jar
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
</dependencies>
2)配置xml文件
resources 中操作
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
- jdbc.properties (记录数据库连接的信息,引入mybatis-config.xml配置数据库)
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/你的数据库
username=你的账号
password=你的密码
- 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 resource="jdbc.properties"></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>
<!--*.xml:你所注册绑定的Mapper.xml的全限定名-->
<mapper resource="*.xml"/>
</mappers>
</configuration>
- mybatis工具类(为了获得SqlSession,在until文件夹下)
public class mybatisUntil {
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();
}
}
//返回SqlSession
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
3)pojo类和数据库
-
数据库表
users表
-
pojo类 user
@Data //Lombok插件生成get&set函数
@AllArgsConstructor //Lombok插件生成有参函数
@NoArgsConstructor //Lombok插件生成无参函数
//当然以上可以不用,手动生成也可以
public class user {
private int id;
private String uname;
private String upassword;
}
4)Mapper接口&Mapper.xml
userMapper 接口的方法名和userMapper.xml的代号需要一致
- userMapper 接口
public interface userMapper {
//查询所有users表中的数据
public List<user> selectAll();
}
- 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">
<!--报错“Type interface lzk.dao.userMapper is not known to the MapperRegistry” 原因: 路径间隔是.-->
<mapper namespace="lzk.dao.userMapper">
<!--id:给该sql映射一个代号 resultType:返回的值的数据类型-->
<select id="selectAll" resultType="lzk.pojo.user">
select * from users
</select>
</mapper>
在mybatis-config.xml添加映射
<!--映射器-->
<mappers>
<!--resource:userMapper.xml在resources的路径-->
<mapper resource="userMapper.xml"/>
</mappers>
5)测试
public class test {
@Test
public void test01(){
//获取SqlSession用于执行sql
SqlSession sqlSession= mybatisUntil.getSqlSession();
//获得mapper映射器实例
userMapper userMapper=sqlSession.getMapper(userMapper.class);
//执行sql
List<user> userList=userMapper.selectAll();
//输出
for (user user : userList) {
System.out.println(user);
}
//关闭SqlSession
sqlSession.close();
}
}
二、增删改查
对数库进行操作只要对Mapper接口&Mapper.xml进行修改即可
因为是执行事务,所以没有进行事务提交就没有真正进行数据更改。Therefore,用sqlSession.commit()提交事务在insert、update、delete时
insert
//Mapper接口
//增加一条记录
public int insertInUsers(user user);
//Mapper.xml
//parameterType:参数的数据类型
<insert id="insertInUsers" parameterType="lzk.pojo.user" >
//#{id},#{unmae},#{upassword}对应pojo类属性名
insert into users values(#{id},#{unmae},#{upassword})
</insert>
//测试
@Test
public void test02(){
//获取SqlSession用于执行sql
SqlSession sqlSession= mybatisUntil.getSqlSession();
//获得mapper映射器实例
userMapper userMapper=sqlSession.getMapper(userMapper.class);
//执行sql
int insert=userMapper.insertInUsers(new user(4,"柯基","444"));
//提交事务
if(insert>0)sqlSession.commit();
//关闭SqlSession
sqlSession.close();
}
update
//Mapper接口
//修改一条记录
public int updateAll(user user);
//Mapper.xml
<update id="updateAll" parameterType="lzk.pojo.user">
update users set unmae=#{unmae},upassword=#{upassword} where id=#{id}
</update>
//测试
@Test
public void test03(){
//获取SqlSession用于执行sql
SqlSession sqlSession= mybatisUntil.getSqlSession();
//获得mapper映射器实例
userMapper userMapper=sqlSession.getMapper(userMapper.class);
//执行sql
int update=userMapper.updateAll(new user(4,"keji","123"));
//提交事务
if(update>0)sqlSession.commit();
//关闭SqlSession
sqlSession.close();
}
delete
//Mapper接口
//删除一条记录
public int deleteById(int id);
//Mapper.xml
<delete id="deleteById" parameterType="int">
<!--#{id}对应参数id-->
delete from users where id=#{id}
</delete>
//测试
@Test
public void test04(){
//获取SqlSession用于执行sql
SqlSession sqlSession= mybatisUntil.getSqlSession();
//获得mapper映射器实例
userMapper userMapper=sqlSession.getMapper(userMapper.class);
//执行sql
int delete=userMapper.deleteById(4);
//提交事务
if(delete>0)sqlSession.commit();
//关闭SqlSession
sqlSession.close();
}
select多表
resultMap:
association – 一个复杂类型的关联;许多结果将包装成这种类型
嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
collection – 一个复杂类型的集合
嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
//mysql
create table teacher(
tid int PRIMARY key,
tname varchar(20)
);
create table student(
sid int PRIMARY key,
sname varchar(20),
spassword varchar(15),
tid int,
foreign key (tid) REFERENCES teacher(tid)
);
一个老师教授n个学生 (一对多)
生成student和teacher类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class student {
private int sid;
private String sname;
private String spassword;
private int tid;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class teacher {
private int tid;
private String tname;
private List<student> students;
}
//Mapper接口
public teacher TAndS(int id);
//Mapper.xml
<select id="TAndS" resultMap="teacherAstudent">
select *
from student join teacher on student.tid=teacher.tid
where teacher.tid=#{id}
</select>
<resultMap id="teacherAstudent" type="lzk.pojo.teacher">
<result property="tid" column="tid"></result>
<result property="tname" column="tname"></result>
<collection property="students" ofType="lzk.pojo.student">
<result property="sid" column="sid"></result>
<result property="sname" column="sname"></result>
<result property="spassword" column="spassword"></result>
<result property="tid" column="tid"></result>
</collection>
</resultMap>
//测试
@Test
public void test05(){
//获取SqlSession用于执行sql
SqlSession sqlSession= mybatisUntil.getSqlSession();
//获得mapper映射器实例
userMapper userMapper=sqlSession.getMapper(userMapper.class);
//执行sql
teacher teacher = userMapper.TAndS(1);
System.out.println(teacher);
//关闭SqlSession
sqlSession.close();
}
n个学生由一个老师教导 (多对一)
生成student和teacher类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class student {
private int sid;
private String sname;
private String spassword;
private teacher teacher;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class teacher {
private int tid;
private String tname;
}
//Mapper接口
//多对一
public student TAndS();
//Mapper.xml
<select id="SAndT" resultMap="studentAteacher">
select *from student join teacher on student.tid=teacher.tid
</select>
<resultMap id="studentAteacher" type="lzk.pojo.student">
<result property="sid" column="sid"></result>
<result property="sname" column="sname"></result>
<result property="spassword" column="spassword"></result>
<association property="teacher" javaType="lzk.pojo.teacher" >
<result property="tid" column="tid"></result>
<result property="tname" column="tname"></result>
</association>
</resultMap>
//测试
@Test
public void test06(){
//获取SqlSession用于执行sql
SqlSession sqlSession= mybatisUntil.getSqlSession();
//获得mapper映射器实例
userMapper userMapper=sqlSession.getMapper(userMapper.class);
//执行sql
List<student> studentList = userMapper.SAndT();
for (student student : studentList) {
System.out.println(student);
}
//关闭SqlSession
sqlSession.close();
}
三、xml配置
mybatis-config.xml中configuration的配置顺序要按如下顺序
settings
日志
设置名: logImpl
描述: 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
有效值: SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
默认值: 未设置
功能:打印并记录你对数据库的操作
- STDOUT_LOGGING
//mybatis-config.xml
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
- LOG4J
1、导包
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2、log4j.properties(log4j配置信息)
#将等级为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
#文件输出的相关设置 ./log/lzk.log:在根目录下创建log(装载日志文件lzk.log)
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/lzk.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
3、日志选择
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
并生成日志
在配置中设置文件位置等信息
typeAliases(类别名)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。在要输入全限定名时,输入type后的别名即可。例如:
<settings>***</settings>
//typeAliases要在setting下面设置
<typeAliases>
<typeAlias type="userMapper" alias="lzk.dao.userMapper"> </typeAlias>
</typeAliases>
四、注解开发
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
1)注册映射
//mybatis-config.xml
<mappers>
//studentMapper接口
<mapper class="lzk.dao.studentMapper"/>
</mappers>
2)书写语句
//studentMapper接口
public interface studentMapper {
@Select("select * from student")
List<student> getAllStudent();
@Insert("insert into student values(#{id},#{sname},#{spassword},#{tid})")
int insertInStudent(student student);
@Update("update users set sname=#{sname},spassword=#{spassword} where id=#{uid}")
int updateById(@Param("uid") int id);
//@Delete("***")
}
注意
测试
@Test
public void test07(){
//获取SqlSession用于执行sql
SqlSession sqlSession= mybatisUntil.getSqlSession();
//获得mapper映射器实例
studentMapper studentMapper=sqlSession.getMapper(studentMapper.class);
//执行sql
List<student> studentList = studentMapper.getAllStudent();
for (student student : studentList) {
System.out.println(student);
}
//关闭SqlSession
sqlSession.close();
}
五、动态sql
使用类似jstl中的if、choose、foreach达到动态组成sql的效果
//引子
如何做到操作时根据参数动态操作数据?
1、没有参数时可以操作全部
2、有参数是可以根据参数的限制操作
查询sql语句: select * from users
上面显然是不能满足所有的要求
下面用官方文档的例子
if
<!--都能去掉标签内的一些错误以达到sql语句无错-->
<where></where>
//只有尖括号的内容不为空才显示
<set></set>
//和<where> 一样
<if 关系式 ></if>
//关系式为真才显示尖括号的内容
//<when>和<if>同理
<choose>
<when 关系式>内容1</when>
<when 关系式>内容2</when>
<otherwise>内容3</otherwise>
</choose>
//和switch一个理
foreach 使用场景是对集合进行遍历
<select id="findActiveBlogWithTitleLike" resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="title != null">
AND title like #{title}
</if>
</where>
</select>
<!--
查询BLOG表,
若参数title == null sql语句为 SELECT * FROM BLOG
反之sql语句为 SELECT * FROM BLOG where title like #{title}
注意 在<if>可以除去多余的and、or等
-->
choose
<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>
<!--
查询BLOG表,
若参数title != null sql语句为
SELECT * FROM BLOG WHERE state = ‘ACTIVE’ and title like #{title}
若参数author != null and author.name != null sql语句为
SELECT * FROM BLOG WHERE state = ‘ACTIVE’ AND author_name like #{author.name}
反之sql语句为 SELECT * FROM BLOG WHERE state = ‘ACTIVE’ AND featured = 1
注意 在<when>也可以除去多余的and、or等
-->
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>
<!--
查询POST表,别名为P,
SELECT * FROM POST P WHERE ID in (内容)
遍历list集合,获得所有对象内容
item="item" 遍历到的对象
index="index" 遍历的次数
collection="list" 集合类型
open="(" separator="," close=")" 给所获得内容外加一个(),每个数据项之间用','隔开
-->
六、缓存
类似操作系统内存管理中分页、分段中的快表,记录寻找过的数据在缓存中,若下次寻找先找缓存,若没有再执行sql语句查询,减少开销
<!--
更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
-->
<cache
<!---在缓存中的数据项满了的替换方式,类似页面置换算法->
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
开启和设置
<!---mybatis-config.xml->
<!---默认一级缓存是开启的->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!---设置,开启二级缓存->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
一级缓存&二级缓存
注意缓存失效
- 执行增删改会刷新缓存
- 手动清楚缓存
终于搞完!
更多详情请看官方文档!
若有错,请大家指出!
【回见】