MyBatis
前言
- 这篇文章是我学习mybatis框架阶段整理出的知识点,代码部分截取了我在idea练习案例时觉得比较重要的部分。整片文章相对全面且通俗易懂,希望能帮助到MyBatis框架的初学者。
框架及三层架构介绍
1.三层架构介绍
(1)三层架构介绍
- 界面层: 和用户打交道的, 接收用户的请求参数, 显示处理结果(jsp ,html ,servlet)
- 业务逻辑层: 接收了界面层传递的数据,计算逻辑,调用数据库,获取数据
- 数据访问层: 就是访问数据库, 执行对数据的查询,修改,删除等等
(2)三层架构对应框架
- 界面层—servlet—springmvc(框架)
- 业务逻辑层—service类–spring(框架)
- 数据访问层—dao类–mybatis(框架)
2.框架介绍
框架是一个模块
- 框架中定义好了一些功能。这些功能是可用的。
- 可以加入项目中自己的功能, 这些功能可以利用框架中写好的功能
框架特点:
- 框架一般不是全能的, 不能做所有事情
- 框架是针对某一个领域有效。 特长在某一个方面,比如mybatis做数据库操作强,但是他不能做其它的
- 框架是一个软件
3.Mybatis框架
(1)简介:
早期叫做ibatis,mybatis是sql映射框架
(2)Mybatis功能:
1. 提供了创建Connection ,Statement, ResultSet的能力 ,不用开发人员创建这些对象了
2. 提供了执行sql语句的能力, 不用手动执行sql
3. 提供了循环sql, 把sql的结果转为java对象, List集合的能力
4. 提供了关闭资源的能力,不用手动关闭Connection, Statement, ResultSet
- 开发人员做的是: 提供sql语句
(3)总结:
mybatis是一个sql映射框架,提供的数据库的操作能力。增强的JDBC
入门案例
-
创建数据表
-
引入maven依赖
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
- 编写Dao接口
public interface StudentDao {
/*查询全部学生信息*/
List<Student> selectAllStudents();
/*插入学生信息*/
int insertStudent(Student student);
}
- 编写Dao映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--指定约束条件,表示mybatis将会执行这些sql语句-->
<!--作用:限制,检查在当前文件中出现的标签,属性是否符合mybatis要求-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper:当前文件根标签-->
<!--namespace:命名空间,使用dao接口的全限定名称-->
<!--在当前文件中,使用特定的标签,表示数据库的特定操作-->
<mapper namespace="com.dao.StudentDao">
<!--id: sql语法的标识,mybatis使用id值找到对应sql语句,id使用对应的方法名称-->
<!--查询: resultType: 表示结果类型,使用类的全限定名称-->
<select id="selectAllStudents" resultType="com.bean.Student">
/*直接写入sql语句*/
select * from Student
</select>
<!--插入-->
<insert id="insertStudent">
insert into student values(#{id},#{name},#{email},#{age});
</insert>
</mapper>
- 创建主配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--mybatis主配置文件-->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--环境配置,数据库的连接信息
default:必须与某个environment id相同,告诉mybatis使用哪个数据库连接信息(访问哪个数据库)-->
<environments default="development">
<!--一个数据库的配置(环境),id:表示环境的名称(自定义)-->
<environment id="development">
<!--mybatis事务类型, type:JDBC(表示使用JDBC中commit,rollback做事物处理)-->
<transactionManager type="JDBC"/>
<!--表示数据源,连接数据库 type:表示数据源的类型,POOLED:表示连接池-->
<dataSource type="POOLED">
<!--连接具体内容-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="502502"/>
</dataSource>
</environment>
</environments>
<!--sql mapper(sql映射文件) 位置-->
<mappers>
<!--指定文件位置-->
<mapper resource="com/dao/StudentDao.xml"/>
</mappers>
</configuration>
可选择是否添加日志
<!--添加日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
- 创建测试
session.方法(Student.xml中mapper的 namespace.id)
openSession():无参默认非自动提交,提交需加入:session.commit()
openSession(true):自动提交
public class StudentTest {
/*获取SqlSession对象*/
private static SqlSession utils() throws IOException {
/*读取mybatis.xml配置文件*/
InputStream stream = Resources.getResourceAsStream("mybatis.xml");
/*创建SqlSessionFactory对象,获取SqlSession*/
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(stream);
/*获取SqlSession对象*/
SqlSession session = factory.openSession();
return session;
}
/*查询操作*/
@Test
public void Test1() throws IOException {
SqlSession session =StudentTest.utils();
/*执行SqlSession的selectAllStudents方法*/
List<Student> studentList = session.selectList("com.dao.StudentDao.selectAllStudents");
for (Student student:studentList){
System.out.println(student);
}
/*关闭SqlSession对象*/
session.close();
}
/*插入操作*/
@Test
public void Test2() throws IOException {
SqlSession session = StudentTest.utils();
Student student = new Student(3, "qbl", "qbl@qq.com", 58);
int insert = session.insert("com.dao.StudentDao.insertStudent",student);
/*mybatis默认不提交事物,在insert,update,delete之后需要手动提交事物*/
session.commit();
session.close();
System.out.println("插入的数据数为: "+insert);
}
}
- 补充:
<!--更改-->
<update id="updateStudent">
update student set name=#{name},email=#{email},age=#{age} where id=#{id};
</update>
<!--删除-->
<delete id="deleteStudent">
delete from student where id=#{id};
</delete>
MyBatis对象分析
1.模板的使用
- 使用模板后,创建该类型文件即可自动生成模板中代码
2.对象分析
(1) Resources 类
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返 回不同类型的 IO 流对象。
(2) SqlSessionFactoryBuilder 类
SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 由 于 SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将 该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。
(3) SqlSessionFactory 接口
SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用 只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。
-
openSession(true):创建一个有自动提交功能的 SqlSession
-
openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
-
openSession():同 openSession(false)
(4) SqlSession 接口
SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以 SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。
SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将 其关闭。再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭。
MyBatis动态代理DAO
1.DAO动态代理实现CRUD
MyBatis动态代理:可以去掉Dao接口实现类
(1)只需在接口中定义方法,并在MyBatisDao.xml配置文件中创建对应id的sql语句
public interface StudentDao {
List<Student> selectAllStudents() throws IOException;
}
<mapper namespace="com.dao.StudentDao">
<select id="selectAllStudents" resultType="com.bean.Student">
select * from student;
</select>
</mapper>
(2)在调用并执行sql语句时,只需调用sqlSession对象的getMapper()方法,即可获取指定接口的实现类对象。
(MyBatisUtils为获取sqlSession对象的工具类)
MyBatisUtils:
public static SqlSession createSqlSession() throws IOException {
/*读取mybatis.xml配置文件*/
InputStream stream = Resources.getResourceAsStream("mybatis.xml");
/*创建SqlSessionFactory对象,获取SqlSession*/
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(stream);
/*获取SqlSession对象*/
SqlSession session = factory.openSession(true);
return session;
}
测试:
@Test
public void Test1() throws IOException {
SqlSession sqlSession = MyBatisUtils.createSqlSession(); //获取sqlSession对象
StudentDao mapper = sqlSession.getMapper(StudentDao.class); //获取接口实现类对象
List<Student> students = mapper.selectAllStudents(); //调用接口实现类中的方法
for (Student student: students){
System.out.println(student);
}
}
2.定义接口传入参数
(1)一个简单参数
- 在接口中定义需要传入参数的方法
Student selectStudentById(int id);
Student selectStudentByName(String name);
- 在xml配置文件中:(参数的数据类型可写可不写)
<!--parameterType: 传入参数的数据类型的全类名,可加可不加-->
<select id="selectStudentById" resultType="com.bean.Student" parameterType="java.lang.Integer">
select * from student where id=#{id};
</select>
<select id="selectStudentByName" resultType="com.bean.Student">
select * from student where name=#{name};
</select>
(2)多个简单参数@Param
- 在DAO接口中
@Param(“studentId”) int id : 表示给id属性起别名,在DAO.xml文件中,#{student}所填入的值
List<Student> selectStudentByIdAndName(@Param("studentId") int id, @Param("studentName") String name);
- 在DAO.XML文件中
<select id="selectStudentByIdAndName" resultType="com.bean.Student">
select * from student where id=#{studentId} or name=#{studentName};
</select>
- 测试
@Test
public void Test2() throws IOException {
SqlSession sqlSession = MyBatisUtils.createSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> students = studentDao.selectStudentByIdAndName(1, "lbw");
}
(3)使用对象传参
- 创建传参类和属性,并生成构造方法
public class ParamType {
public String paramName; //表示姓名
public Integer paramId; //表示id
}
- 在Dao接口中创建方法,参数为ParamType对象
List<Student> selectStudentByParam(ParamType paramType);
- 在Dao.xml配置文件文件中写入当前方法的sql语句
<select id="selectStudentByParam" resultType="com.bean.Student">
select * from mybatis.student where name=#{paramName} or id=#{paramId};
</select>
(4)通过位置传参
- 在Dao中创建方法
List<Student> selectStudentByContext(String name,int id);
- 在Dao.xml写入sql语句
<select id="selectStudentByContext" resultType="com.bean.Student">
select * from mybatis.student where name=#{arg0} or id=#{arg1};
</select>
(4)通过Map集合传参
- 在Dao中创建方法
List<Student> selectStudentByMap(Map<String,Object> map);
- 在Dao.xml写入sql语句
<select id="selectStudentByMap" resultType="com.bean.Student">
select * from mybatis.student where name=#{studentName} or id=#{studentId};
</select>
- 测试,传入Map集合
@Test
public void Test8() throws IOException {
SqlSession sqlSession = MyBatisUtils.createSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
HashMap<String, Object> map = new HashMap<>();
map.put("studentName","cxk");
map.put("studentId",4);
List<Student> students = studentDao.selectStudentByMap(map);
for (Student student:students){
System.out.println(student);
}
}
3.#和$
- #:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替 sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法
- ** ∗ ∗ : 字 符 串 替 换 , 告 诉 m y b a t i s 使 用 ** :字符串替换,告诉 mybatis 使用 ∗∗:字符串替换,告诉mybatis使用包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的 内容连接起来。主要用在替换表名,列名,不同列排序等操作
4.ResultType
(1)简介
执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。 注意如果返回的是集 合,那应该设置为集合包含的类型,而不是集合本身。resultType 和 resultMap,不能同时使用。
(2)别名
在MyBatis.xml主文件中,定义别名。在dao.xml配置文件中可使用定义的别名
- 方式一:type为类型的全路径,alias为别名
<typeAliases>
<typeAlias type="com.bean.Student" alias="Student"/>
<typeAlias type="com.param.ParamType" alias="ParamType"/>
</typeAliases>
使用:
<select id="selectStudentByIdAndName" resultType="Student">
select * from mybatis.student where id=#{studentId} or name=#{studentName};
</select>
- 方式二:name为包名,包下的所有类别名就为类名
<typeAliases>
<package name="com.bean"/>
</typeAliases>
使用:
<select id="selectStudentByIdAndName" resultType="Student">
select * from mybatis.student where id=#{studentId} or name=#{studentName};
</select>
5.ResultMap
(1)简介
结果映射:指定列明和java对象的属性对应关系
resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。 常用在列名和 java 对象属性名不一样的情况。
(2)运用
- 在dao中创建方法
List<Student> selectAllStudents();
- 在dao.xml配置文件中定义
(1)定义resultMap:指定查询出来的每个字段的值赋给哪个属性
(2)在select标签中运用resultMap属性,选择需要调用的resultMap标签(id值)
<!--定义resultMap
表示将指定字段的值赋给指定属性
id:自定义名称
type:定义类型的全限定名称
-->
<resultMap id="studentMap" type="com.bean.Student">
<!--主键列,使用id标签 column:列名,property:类的属性名-->
<id column="id" property="id"/>
<!--非主键列,使用result标签,-->
<result column="name" property="name"/> <!-- 表的name字段—>类的name属性 -->
<result column="email" property="email"/>
<result column="age" property="age"/>
</resultMap>
<!--定义sql语句 resultMap:指定定义好的resultMap-->
<select id="selectAllStudents" resultMap="studentMap">
select * from mybatis.student;
</select>
**注意:**resultType和resultMap二者选其一
6.模糊查询
模糊查询
- 方式一:
传入模糊查询where条件的完整格式
dao:
List<Student> selectStudentLike(@Param("name") String name);
dao.xml:
<select id="selectStudentLike" resultType="com.bean.Student">
select * from mybatis.student where name like #{name};
</select>
测试:
List<Student> students = mapper.selectStudentLike("%b%");
- 方式二:
在dao.xml的where条件已经书写好模糊查询格式,只需传入具体内容
dao:
List<Student> selectStudentLike2(@Param("name") String name);
dao.xml:
<select id="selectStudentLike2" resultType="com.bean.Student">
select * from mybatis.student where name like "%" #{name} "%";
</select>
测试:
List<Student> students = mapper.selectStudentLike2("b");
动态sql
- 动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。
- 常用的动态sql标签有if,where,foreach,choose等
1.if标签
将满足if条件的语句加入到sql语句中
<select id="selectStudentIf" resultType="com.bean.Student">
select * from mybatis.student where
<if test="name!=null">
name=#{name}
</if>
<if test="id>0">
or id=#{id}
</if>
</select>
**注:**若前一个条件不满足,后一个条件or会导致sql语法错误
2.Where标签
能更好的避免标签中语法错误问题
<select id="selectStudentWhere" resultType="com.bean.Student">
select * from mybatis.student
<where>
<if test="name!=null">
name=#{name}
</if>
<if test="id!=null">
or id=#{id}
</if>
</where>
</select>
3.foreach标签
处理sql语句中传入多个值得问题
- 方式一
直接传入sql语句中所需的字符
List<Student> selectStudentForEach(List<Integer> list);
collection:遍历的集合或数组类型(list,array)
item:遍历的成员
open:开始字符
close:结束字符
separator:分隔符
select id="selectStudentForEach" resultType="com.bean.Student">
select * from mybatis.student where id in
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
- 方式二
传入对象
List<Student> selectStudentForEach2(List<Student> studentList);
<select id="selectStudentForEach2" resultType="com.bean.Student">
select * from mybatis.student where id in
<foreach collection="list" item="student" open="(" close=")" separator=",">
#{student.id}
</foreach>
</select>
4.动态代码片段
- 可定义一段sql语句,在需要重复使用此sql语句的地方导入(复用sql语句)
<!--sql语句截取片段-->
<sql id="sql">
select * from mybatis.student where
</sql>
<!--引入片段-->
<select id="selectSomeStudent" resultType="com.bean.Student">
<include refid="sql"/>
id>#{id}
</select>
MyBatis配置文件
1.主配置文件
主配置文件 之前项目中使用的 mybatis.xml 是主配置文件。
主配置文件特点:
- 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">
2.根元素
<configuration>
3.主要包含内容:
-
定义别名
-
数据源
-
mapper 文件
2.dataSource标签
Mybatis 中访问数据库,可以连接池技术,但它采用的是自己的连接池技术。在 Mybatis 的 mybatis.xml 配置文件中,通过
<dataSource type=”pooled”>
来实现 Mybatis 中连接池的配置。
dataSource 类型:
- UNPOOLED 不使用连接池的数据源
- POOLED 使用连接池的数据源
- JNDI 使用 JNDI 实现的数据源
3.指定properties资源文件
- 在同resources目录下创建jdbc.properties资源文件
mybatis.url=jdbc:mysql://localhost:3306/mybatis
mybatis.username=root
mybatis.password=502502
mybatis.driverClassName=com.mysql.cj.jdbc.Driver
- 在主配置文件中指定并使用资源文件
<properties resource="jdbc.properties"/>
<!--指定后,dataSource的property标签中的value属性值修改为${...}-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--连接具体内容,value中都修改为properties指定的key-->
<property name="driver" value="${mybatis.driverClassName}"/>
<property name="url" value="${mybatis.url}"/>
<property name="username" value="${mybatis.username}"/>
<property name="password" value="${mybatis.password}"/>
</dataSource>
</environment>
</environments>
4.指定多个mapper文件
- 方式一:
写多行mapper resource
<mappers>
<mapper resource="com/dao/MyBatisDao.xml"/>
<mapper resource="com/dao/MyBatisDao2.xml"/>
</mappers>
- 方式二:
写多个mapper文件所在的包路径
<mappers>
<package name="com.dao"/>
</mappers>
```
4.指定多个mapper文件
- 方式一:
写多行mapper resource
<mappers>
<mapper resource="com/dao/MyBatisDao.xml"/>
<mapper resource="com/dao/MyBatisDao2.xml"/>
</mappers>
- 方式二:
写多个mapper文件所在的包路径
<mappers>
<package name="com.dao"/>
</mappers>
- 关于MyBatis框架的拙作就到这里,欢迎大家补充