mybatis是支持普通SQL查询、存储过程和高级映射的优秀持久层框架。
我们把Mybatis的功能架构分为三层:
1.API接口层 2.数据处理层 3.基础支撑层
**API接口:**提供给外部使用的API接口,开发人员使用本地API接口操作数据库。接口层一收到调用请求,就会调用数据处理层进行具体的数据处理。
**数据处理层:**负责具体的SQL查询,SQL解析、SQL执行以及执行结果集映射的处理。主要目的是根据调用进行一次操作数据库
**基础支撑层:**负责最基础的支撑,包括 连接管理、事务管理、配置加载、缓冲加载。这些都是公用的的基础组件。
框架架构讲解:
mybatis结构
(1)加载配置:配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
(2)SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。
(3)SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。
(4)结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。
持久化
CREATE DATABASS mybatis;创建表
USE mybatis
go
CREATE TABLE Users(
id int not null PRIMARY KEY,
name varchar default NULL,
pwd varchar default NULL
)插入值
insert Users(id,name,pwd)
values (1,'张三','123456')
insert Users(id,name,pwd)
values (2,'李四','123456')
insert Users(id,name,pwd)
values (3,'王五','123456')另外一种值插入方法
insert into Users
select 1,'张三','123456'
union 导入依赖
sqlServer驱动
<!--sqlServer驱动-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>8.2.2.jre8</version>
</dependency>mybatis
<!--mybatis-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>junit
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>创建Module 作为子模块
<?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.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://localhost:1433;database=mybatis;useSSL=true&useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="sa"/>
<property name="password" value="1582183834"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/Dao/UsersMapper.xml"/>
</mappers>
</configuration>编写工具类 加载使用
public class UsersUtils {
private static SqlSessionFactory sqlSessionFactory;
static{
//获取sqlSessionFactory对象
try {
String resource ="mybatis-config.xml";
InputStream resourceAsStream = Resources.getResourceAsStream(resource);
sqlSessionFactory =new SqlSessionFactoryBuilder().build(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession实例
//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
// SqlSession sqlSession = sqlSessionFactory.openSession();
// return sqlSession;
}
}public class Users implements Serializable {
private int id;
private String name;
private String pwd;
public Users() {
}
public Users(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "Users{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}interface UsersDao {
List<Users> getUsersDaoList();
}<?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.Dao.UsersDao">
<select id="getUsersDaoList" resultType="com.pojo.Users">
select * from Users
</select>
</mapper>namespace=“com.Dao.UsersDao”
全限命名法,namespace 表示和某一个类或接口 相匹配
id=“getUsersDaoList”
Select 中的ID表示查询的方法
resultType=“com.pojo.Users”
返回单个的类型,必须表示返回类型所对应的实体类。
一般在Text下创建和代码相对应的目录进行测试。

public class Text {
@Test
public void text(){
//加载resources资源
//获取SqlSession对象
SqlSession sqlSession = UsersUtils.getSqlSession();
//执行SQL
UsersDao mapper = sqlSession.getMapper(UsersDao.class);
List<Users> usersDao = mapper.getUsersDaoList();
for (Users users : usersDao) {
System.out.println(users);
}
//关闭资源
sqlSession.close();
}
}
org.apache.ibatis.binding.BindingException: Type interface com.Dao.UsersDao is not known to the MapperRegistry.
在核心配置文件中没有没有将UsersDao的xml文件配置注册
<mappers>
<mapper resource="com/Dao/UsersMapper.xml"/>
</mappers>将UsersDao的xml文件配置到Mybatis核心配置文件当中
IOException: Could not find resource com/Dao/UsersMapper.xml
1.没有编写UsersMapper.xml配置文件。
2.因为在Maven项目中,约定大于配置,所以需要手动将Java中的xml打包带出
1.编写UsersMapper.xml文件
2.在Pom文件下加上Build
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
UsersDao接口
//通过id查询用户
Users getUsersById(int id);映射文件
<select id="getUsersById" resultType="com.pojo.Users" parameterType="int">
select * from Users where id=#{id}
</select>测试结果
@Test
public void Text01(){
SqlSession sqlSession = UsersUtils.getSqlSession();
UsersDao mapper = sqlSession.getMapper(UsersDao.class);
Users usersById = mapper.getUsersById(1);
System.out.println(usersById);
sqlSession.close();
}UsersDao接口
//增加用户
int InsertUser(Users users);映射文件
<insert id="InsertUser" parameterType="com.pojo.Users">
insert Users(id,name,pwd) values(#{id},#{name},#{pwd})
</insert>测试
//增加用户
@Test
public void Text02(){
SqlSession sqlSession = UsersUtils.getSqlSession();
UsersDao mapper = sqlSession.getMapper(UsersDao.class);
int s = mapper.InsertUser(new Users(4, "五百", "123456"));
if (s>0){
System.out.println("增加用户成功");
}
//增删改需要提交事务,否则无法更改
sqlSession.commit();
sqlSession.close();
}UsersDao接口
//更改用户数据
int UpdataUser(Users users);映射文件
<update id="UpdataUser" parameterType="com.pojo.Users">
update Users set name=#{name},pwd=#{pwd} where id=#{id};
</update>测试
//修改用户 将四号用户的名字改为六百
@Test
public void text03(){
SqlSession sqlSession = UsersUtils.getSqlSession();
UsersDao mapper = sqlSession.getMapper(UsersDao.class);
int liu = mapper.UpdataUser(new Users(4, "六百", "123456"));
if (liu>0){
System.out.println("修改用户成功");
}
//提交事务
sqlSession.commit();
sqlSession.close();
}UsersDao接口
//删除用户数据
int DelectUser(int id);映射文件
<delete id="DelectUser" parameterType="int">
delete from Users where id=#{id};
</delete>测试
@Test
public void text04(){
SqlSession sqlSession = UsersUtils.getSqlSession();
UsersDao mapper = sqlSession.getMapper(UsersDao.class);
int i = mapper.DelectUser(4);
if (i>0){
System.out.println("删除用户成功");
}
sqlSession.commit();
sqlSession.close();
}UsersDao接口
public interface UsersDao {
//获取列表
List<Users> getUsersDaoList();
//通过id查询用户
Users getUsersById(int id);
//增加用户
int InsertUser(Users users);
//更改用户数据
int UpdataUser(Users users);
//删除用户数据
int DelectUser(int id);
}映射文件
<?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.Dao.UsersDao">
<select id="getUsersDaoList" resultType="com.pojo.Users">
select * from Users
</select>
<select id="getUsersById" resultType="com.pojo.Users" parameterType="int">
select * from Users where id=#{id}
</select>
<insert id="InsertUser" parameterType="com.pojo.Users">
insert Users(id,name,pwd) values(#{id},#{name},#{pwd})
</insert>
<update id="UpdataUser" parameterType="com.pojo.Users">
update Users set name=#{name},pwd=#{pwd} where id=#{id};
</update>
<delete id="DelectUser" parameterType="int">
delete from Users where id=#{id};
</delete>
</mapper>首先声明xml中各个配置设置的位置是固定不变的,否则会出现异常

必须遵循下面的顺序进行设置。
(properties–settings–typeAliases–typeHandlers–objectFactory–objectWrapperFactory–reflectorFactory–plugins–environments–databaseIdProvider–mappers)"
目前我们学过的属性文件db.properties
在xml文件当中,为了实现我们可以动态修改xml文件,可以在外部设置属性文件引用到mybatis-config.xml文件当中。
属性配置有两种插入方法
1.内部引入
<properties >
<property name="username" value="sa"/>
<property name="password" value="1582183834"/>
</properties>2.外部引入
2.1 首先编写一个properties属性文件。
driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
url=jdbc:sqlserver://localhost:1433;database=mybatis;useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=sa
password=1582183834然后在mybatis-config.xml文件当中
<properties resource="db.properties"></properties>环境中属性的更改
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>通过${}以实现动态获取properties属性文件当中的属性
若两部分都有部署,首先会执行内部的xml,再执行外部的属性资源,但是内部的某些属性会被外部属性覆盖!
类型别名相当于对动态SQL中的返回类型或者参数类型的优化
例如在查询表单的SQL中的返回类型resultType的返回类型是一个对象
<select id="getUsersDaoList" resultType="com.pojo.Users">
select * from Users
</select>这样些写较为麻烦,所以为这个类型设置一个别名
<typeAliases>
<typeAlias type="com.pojo.Users" alias="Users"/>
</typeAliases>这样设置类型为Users类的别名就变为Users
<select id="getUsersDaoList" resultType="Users">
select * from Users
</select>package类型别名
package 顾名思义是包 package类型别名,即是扫描包
<typeAliases>
<package name="com.pojo"/>
</typeAliases>扫描包
每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。
例如 在pojo包下有一个名为User的类,那么扫描后的返回类型就为user
注解别名
和上侧相同,当包下的类有注解时,注解为Alias(“”)
则此时的返回类型就为注解内容,并且和类名无关
例如 在pojo包下有一个名为User的类,注解为Alias(“hello”),那么扫描后的返回类型为hello,并不为user
换一种说法,也就是在扫描包别名是,注解的优先级大于类名别名优先级
映射器
映射器配置共有3中配置方法
1.resource
<mappers>
<mapper resource="com/Dao/UsersMapper.xml"/>
</mappers>配置这种资源,每一层需要斜杠间隔(/)
2.class
<mappers>
<mapper class="com.Dao.UsersMapper"/>
</mappers>使用映射器中的class映射必须遵守以下规则,否则就会报错
3.package扫描方法
<mappers>
<package name="com.Dao"/>
</mappers>使用映射器中的package方法也必须遵循以下规则
另外还有一种url路径反射,因为路径问题,所以很难寻找(不建议使用)。
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>mybatis官方url定位介绍
当pojo中的字段与数据库中的字段不同时,则可能会导致项目某些功能运行失败

因为字段名不一致,运行结果导致结果查询失败

方法一
(起别名)
select * from Users相当于
select id,name,pwd from Users为此,我们必须为pwd起一个别名
select id,name,pwd as password from Users然后就可以查询到password这个字段对应在数据库pwd中的值了
方法二;
(更改前)使用ResultMap集合
<select id="getUsersDaoList" resultType="users">
select id,name, pwd as password from Users
</select>(更改后)其中resultType更换为resultMap
<select id="getUsersDaoList" resultMap="usersResultMap">
select id,name, pwd from Users
</select>然后追加一个属性
<resultMap id="" type="">
<result column="" property=""/>
</resultMap>此处标签属性介绍
id - 相当于绑定标识 -在这里绑定到 resultMap=“usersResultMap” -即id=“usersResultMap”
type-相当于返回类型–返回类型为实体类中的类—type =“Users”
column–列表,数据库中的字段–column=“pwd”
property–属性,java类中字段名–property=“password”
<resultMap id="usersResultMap" type="users">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>当然,在我们这个实例当中,字段id和name和数据库中的字段并没有区别,所以我们可以适当进行删减
<resultMap id="usersResultMap" type="users">
<result column="pwd" property="password"/>
</resultMap>这样就体现到了resultMap的一个优点
当连表查询等复杂查询时,建议使用resultMap 进行项目创建
当仅仅是简单查询时,不建议使用resultMap
为了保证项目的简洁,建议在创建实体类时,最后将数据库和实体类中的字段名一一对应。
日志简而言之是提供操作记录,有时便于我们进行排错
日志工厂在设置中进行添加,即

key–> logImpl
value—>
重要:使用日志工厂时,必须保证大小写,数量一致,空格多少也会导致错误。
STDOUT_LOGGING
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>观察控制台输出结果
前部分一些处理(暂且不看)


总体来说便于理解如何实现SQL查询
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>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/caiji.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将大括号改为英文下的
运行后可能出现的问题

日志目录下的log存在打不开的现象
出现的原因可能有
解决
Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下:
%m输出代码中指定的消息;
%M输出打印该条日志的方法名;
%p输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL;
%r输出自应用启动到输出该log信息耗费的毫秒数;
%c输出所属的类目,通常就是所在类的全名;
%t输出产生该日志事件的线程名;
%n输出一个回车换行符,Windows平台为"rn”,Unix平台为"n”;
%d输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy-MM-ddHH:mm:ss,SSS},输出类似:2002-10-1822:10:28,921;
%l输出日志事件的发生位置,及在代码中的行数。
首先需要一个Logger对象,获取当前类的信息,并通过这个对象来进行操作日志
static Logger logger = Logger.getLogger(Text.class); //因为日志好多都需要使用,所以要提升作用域然后进行一个简单的测试
static Logger logger = Logger.getLogger(Text.class);
@Test
public void TestLOG4J(){
logger.info("INFO:进入方法");
logger.debug("DEBUG:进入方法");
logger.error("ERROR:进入方法");
}其中,logger.info logger.debug logger.error 相当于java中的System.out.println()
测试结果

log日志

输出了方法
其中,优先级 Error >Info>debug
OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL 以此递减
首先,如果使用的是SQLServer数据库,那么他的分页方法有四种,并不是Limit关键字进行分页
limit关键字是mySql数据库进行分页操作时的关键字。
在这里使用SQLServer数据库进行分页查询
编写分页查询接口
//分页
List<Users> getUsersLimit(Map<String,Integer> map);采用传递Map接口来传递参数更快捷简单
编写接口配置文件
<select id="getUsersLimit" parameterType="map" resultMap="usersResultMap" >
select top ${pageSize} * from Users where id not in(select top ${pageIndex} id from Users ORDER BY id)
</select>其中usersResultMap绑定在resultMap当中,用于上一次解决字段名不相同问题
{pageSize} 以及 {pageIndex} 为自定义名字,用于传递参数,在测试类当中我们将以此为Key值进行传递参数。
需要注意的是:
在编写SQL语句时,一般在数据库具有字段可变参格式 例如,id=#{id}
自行构造参数传递时,例如分页查询,其传递参数仅仅为#{pageSize}
当SQL语句当中top 等关键字出现时,传递的参数格式就需要 ${pageSize}
原因是top关键字后占位符不能使用#{}来进行占位 但是有可能会有注入问题出现
编写Test测试
@Test
public void TestLimit(){
SqlSession sqlSession = UsersUtils.getSqlSession();
UsersMapper mapper = sqlSession.getMapper(UsersMapper.class);
HashMap<String,Integer > map = new HashMap<String,Integer >();
map.put("pageSize",2);
map.put("pageIndex",1);
List<Users> us = mapper.getUsersLimit(map);
for (Users u : us) {
System.out.println(u);
}
sqlSession.close();
}RowBounds查询属于面向对象查询(官方不建议使用)
编写Mapper接口
List<Users> getRowBounds();编写接口配置文件即SQL
<select id="getRowBounds" resultMap="usersResultMap">
select * from Users
</select>测试类
简单查询分页,没有调用UsersMapper接口中的方法,不需要获取其反射对象
@Test
public void TestRowBounds(){
SqlSession sqlSession = UsersUtils.getSqlSession();
RowBounds rowBounds = new RowBounds(1,2);
//另一种获取Mapper接口的方法 //权限命名
List<Users> usersList = sqlSession.selectList("com.Dao.UsersMapper.getRowBounds", null, rowBounds);
for (Users users : usersList) {
System.out.println(users);
}
sqlSession.close();
}编写接口
//注解开发
@Select("select * from Users")
List<Users> getUsersList();将mybatis核心配置文件的映射部分改为Class映射
<mappers>
<mapper class="com.Dao.UsersMapper"></mapper>
</mappers>编写测试类
@Test
public void TestCom(){
SqlSession sqlSession = UsersUtils.getSqlSession();
UsersMapper mapper = sqlSession.getMapper(UsersMapper.class);
List<Users> List = mapper.getUsersList();
for (Users users : List) {
System.out.println(users);
}
sqlSession.close();
}编写接口
//注解开发
@Select("select * from Users")
List<Users> getUsersList();
//增
@Insert("Insert Users (id,name,pwd) values(#{id},#{name},#{password})")
int insertUsers(Users users);
//改
@Update("update Users set name=#{name},pwd=#{password} where id=#{id}")
int updateUsers(Users users);
//删
@Delete("delete from Users where id=#{id}")
int delectUsers(@Param("id") int id);@Param参数注解,后面参数名称
测试类
省略
创建Student表
create table Student(
id int not NULL primary key,
name varchar(20) Null,
tid int null
)创建Teacher表
create table Teacher(
id int not NULL primary key,
name varchar(20) null
)创建外键
alter table Student
add constraint FK_Student_tid foreign key(tid) references Teacher (id)association 多对一 多个学生面对同一个老师
collection 集合 一对多 一个老师拥有多个学生
public class Student {
private int id;
private String name;
private Teacher teacher;
}public class Teacher {
private int id;
private String name;
}<select id="getStudentList" resultMap="TeacherStudent">
select * from Student
</select><select id="getTeacher" resultType="Teacher">
select * from Teacher where id=#{tid}
</select><resultMap id="TeacherStudent" type="Student">
<result property="id" column="id"></result>
<result property="name" column="name"></result>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"></association>
</resultMap><select id="getStudentInformation" resultMap="TeacherStudent2">
select s.id sid, s.name sname, t.name tname from Student s,Teacher t where s.tid=t.id
</select>
<resultMap id="TeacherStudent2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" column="tname" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>接口类
public interface StudentMapper {
//获取学生别表
// @Select("select * from Student")
List<Student> getStudentList();
//获取学生信息
List<Student> getStudentInformation();
}一个老师拥有多个学生
collection 集合
public class Student {
private int id;
private String name;
}public class Teacher {
private int id;
private String name;
private List<Student> students;
}<select id="getTeacherList" resultMap="TeacherStudent">
select * from Teacher where id=#{id}
</select><resultMap id="TeacherStudent" type="Teacher">
<collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudent"/>
</resultMap><select id="getStudent" resultType="Student">
select * from Student where tid =#{id}
</select><select id="getList" resultMap="List">
select s.id sid, s.name sname ,t.id tid ,t.name tname from Student s,Teacher t where s.tid=t.id and s.tid=#{id}
</select>
<resultMap id="List" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" column="tid" ofType="Student" >
<result property="id" column="sid"/>
<result property="name" column="sname"/>
</collection>
</resultMap>接口类
public interface TeacherMapper {
//获取老师列表
List<Teacher> getTeacherList(@Param("id")int id);
//查询全部
List<Teacher> getList(@Param("id")int id);
}动态SQL就是根据不同的条件生成不同的SQL语句
创建表

利用mybatis 添加数据
pojo实体类
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private int views;
}数据库中的字段名与实体类中的横杠不统一
createTime----create_time
解决方法
<setting name="mapUnderscoreToCamelCase" value="true"/>在mybatis-config.xml核心配置文件当中设置
开启驼峰转换
BlogMapper
//添加Blog用户
int addBlogList(Blog blog);BlogMapper.xml
<insert id="addBlogList" parameterType="Blog" >
insert Blog(id,title,author,create_time,views)values(#{id},#{title},#{author},#{createTime},#{views})
</insert>测试类
//添加用户
@Test
public void addBlogList(){
SqlSession sqlSession = UserUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IDUtils.getUUid());
blog.setTitle("JAVA的入门");
blog.setAuthor("咸鱼");
blog.setCreateTime(new Date());
blog.setViews(9999);
mapper.addBlogList(blog);
blog.setId(IDUtils.getUUid());
blog.setTitle("JAVA的开始");
blog.setAuthor("咸鱼");
blog.setCreateTime(new Date());
blog.setViews(8080);
mapper.addBlogList(blog);
blog.setId(IDUtils.getUUid());
blog.setTitle("JAVA的进阶");
blog.setAuthor("咸鱼");
blog.setCreateTime(new Date());
blog.setViews(6666);
mapper.addBlogList(blog);
blog.setId(IDUtils.getUUid());
blog.setTitle("JAVA的精通");
blog.setAuthor("咸鱼");
blog.setCreateTime(new Date());
blog.setViews(9999);
mapper.addBlogList(blog);
sqlSession.close();
}当我们想要做一个类似于查找的功能时,例如通过title和author进行模糊查找
我们可以选择只填写title 或者只填写author
如果仅仅采用编写多个方法来应对不同的需求时,那么这些代码将有很多重复,不简洁
select * from User where title=? and author=?
select * from User where title=?
select * from User where author=?
这样写一个功能 使用3个sql进行多次查询?
这样也太麻烦了
为此
我们将采用动态sql中的if查询
同样是上侧的案例
接口方法:(采用map作为参数进行传值,通过put进行动态添加key,value)
//动态SQLif
List<Blog> getList(Map map);mapper.xml
<select id="getList" 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>首先,先书写一个用于查询全部数据的SQL语句,然后在后添加一个Where 1=1 ,添加where 1=1 的目的就是在没有任何条件下的查询语句 ,其作用和 select * from Blog 作用相等(但是在项目书写代码中,where 1=1并不符合规范,这里使用仅仅是为了学习if,接下来会有解决这个问题的知识。)
然后在使用if语句进行判断,当有title这个值存在时,就把他拼接进去。同理 author也是如此。
这样就使用一个sql语句就解决带有N多种条件的查询啦!
解决where 1=1 的问题
//动态SQLif2 where标签
List<Blog> getList2(Map map);<select id="getList2" parameterType="map" resultType="Blog">
select * from Blog
<where>
<if test="title!=null">
and title =#{title}
</if>
<if test="author!=null" >
and author=#{author}
</if>
</where>
</select>添加where标签,可以在if满足的条件下,自动添加where标签。并且自动检测是否在第一项,自动省略第一个条件的and标签。
另外,有时候where自动省略and 或者or 标签失败。
所以,解决此问题的方法自定义设定
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>prefix------前缀
prefixOverrides------前缀覆盖
//动态SQL update set标签
int updateList(Map map);<update id="updateList" >
update Blog
<set>
<if test="title!=null">title=#{title},</if>
<if test="author!=null">author=#{author}</if>
</set>
where id=#{id}
</update>自动将后面的,进行覆盖或者显现
<trim prefix="SET" suffixOverrides=",">
...
</trim>//choose选择
List<Blog> getListChoose(Map map);<select id="getListChoose" parameterType="map" resultType="Blog">
select * from Blog
<where>
<choose>
<when test="title!=null"> and title=#{title}</when>
<when test="author!=null">and author=#{author}</when>
<otherwise>
and views=#{views}
</otherwise>
</choose>
</where>
</select>choose选择器,相当于java中的while 当第一中符合时,其余的都不会有效
当有一种符合时,其他都会无效。
//sql片段。实现sql复用
List<Blog> getList3(Map map);<select id="getList3" parameterType="map" resultType="Blog">
select * from Blog
<where>
<include refid="if-title-author"></include>
</where>
</select>
<sql id="if-title-author">
<if test="title!=null">
and title =#{title}
</if>
<if test="author!=null" >
and author=#{author}
</if>
</sql>定义sql以实现sql 的复用
最好不要将where等标签放入sql语句当中,以提供sql语句的多次复用
//sqlforeach查询
List<Blog> getList4(Map map);<select id="getList4" parameterType="map" resultType="Blog">
select * from Blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>测试
//sqlforeach
@Test
public void getIfListTest4(){
SqlSession sqlSession = UserUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
ArrayList ids = new ArrayList();
ids.add("1");
ids.add("2");
map.put("ids",ids);
List<Blog> list2 = mapper.getList4(map);
for (Blog blog : list2) {
System.out.println(blog);
}
sqlSession.close();
}
在这里分隔符需要使用or 其他可能会报错
动态SQL,就是在拼接SQL,保证SQL的正确性,按照SQL格式
在Mybatis当中,分为一级缓存和二级缓存
一级缓存和SQLsession同级别
在创建session和关闭session之间有效。
缓存可以缓存所有的select语句,每当出现update、insert、delect出现时,缓存将会失效,将会被刷新
一级缓存是默认缓存

虽然在设置当中默认开启了二级缓存的总开关,但是为了保证代码的可读性,建议在xml核心配置文件当中设置
<setting name="cacheEnabled" value="true"/>在Mapper里添加下面的标签开启二级缓存
<cache/>
(首次)开启sqlsession查询数据库,然后存入一级缓存,当SQLsession关闭后,一级缓存将会存入该Mapper中的二级缓存当中。
(再次)查询过程
r">
and title =#{title} and author=#{author} ```
定义sql以实现sql 的复用
最好不要将where等标签放入sql语句当中,以提供sql语句的多次复用
//sqlforeach查询
List<Blog> getList4(Map map);<select id="getList4" parameterType="map" resultType="Blog">
select * from Blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>测试
//sqlforeach
@Test
public void getIfListTest4(){
SqlSession sqlSession = UserUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
ArrayList ids = new ArrayList();
ids.add("1");
ids.add("2");
map.put("ids",ids);
List<Blog> list2 = mapper.getList4(map);
for (Blog blog : list2) {
System.out.println(blog);
}
sqlSession.close();
}[外链图片转存中…(img-vgNIQlbm-1703315948656)]
在这里分隔符需要使用or 其他可能会报错
动态SQL,就是在拼接SQL,保证SQL的正确性,按照SQL格式
在Mybatis当中,分为一级缓存和二级缓存
一级缓存和SQLsession同级别
在创建session和关闭session之间有效。
缓存可以缓存所有的select语句,每当出现update、insert、delect出现时,缓存将会失效,将会被刷新
一级缓存是默认缓存
[外链图片转存中…(img-TXo9UTXP-1703315948657)]
虽然在设置当中默认开启了二级缓存的总开关,但是为了保证代码的可读性,建议在xml核心配置文件当中设置
<setting name="cacheEnabled" value="true"/>在Mapper里添加下面的标签开启二级缓存
<cache/>(首次)开启sqlsession查询数据库,然后存入一级缓存,当SQLsession关闭后,一级缓存将会存入该Mapper中的二级缓存当中。
(再次)查询过程
先从二级缓存中查询是否有此查询的缓存,若没有,然后在一次缓存当中查询是否有此缓存,如果都没有,那么连接数据库,进行查询。