myBatis 入门学习
0.1 框架和工具类
-
工具类
-
对程序中一小段代码的封装。项目中大多数代码还是需要我们写。
-
-
框架
-
通俗理解框架
-
可以看做一个半成品的软件/项目。使用框架开发项目,项目中半数以上代码就不需要 我们编写了。
-
我们一般需要配置(大多数框架都是重配置轻编码的)+少量编码,就可完成项目中的需求。
-
框架的目的 就是为了简化编码:
eg:Mybatis
。 我们在学习完Mybatis
之后,dao
层会更简单。你只需要写一个dao
接口,然后写一个SQL
语句,dao
层就已经写完了。
-
-
学习步骤
-
这个框架能干什么?
-
导包+配置
-
框架少量的
API
,少量编码
-
0.2 ORM
-
Object Relational Mapping
对象关系映射的思想 -
对象 - Java中的对象 关系-关系型数据库中表的记录 映射 - 一对一关联起来
-
java
项目中的每一个实体类,对应数据库中的一个表;java
类中的属性,对应数据库表中的字段。java
类中的一个实体对象,对应一个数据表中的一条记录 -
全自动
ORM
框架:hibernate
。通过操作实体对象,就可以完成对数据库表中记录的操作。复杂业务性能低下,不可定制,学习成本高。
-
半自动的
ORM
框架:Mybatis
,ibatis
基于
ORM
,但是SQL
语句需要我们自己编写。自己优化SQL
,可定制性强,效率高。
0.3 Mybatis
&原生JDBC
-
原生jdbc
-
注册驱动,设置连接参数 -
获取连接 -
获取执行对象
-
设置
SQL
参数并执行SQL
语句 -
封装结果集并封装成实体对象
-
释放资源
相同的内容已经抽取到工具类中(上述删除线标识的步骤)
模板化(步骤不变,部分步骤相同,上述加粗的内容)的操作,也是可以抽取封装的。
但是相同的步骤中又有不同的地方,不同的地方如果也要实现解耦,需要通过配置来实现
-
-
Mybatis
解决方案-
连接复用:使用数据库连接池初始化并管理连接
-
解耦:将
SQL
语句和设置到SQL
中的参数抽取到xml
配置文件中 -
自动封装:通过反射内省等技术,实现查询结果集字段与实体属性自动映射并赋值
-
-
Mybatis
框架抽取后的样子
-
Mybatis
简介-
是一个数据持久层(
DAO
)框架,封装共性内容让使用者只关注SQL
本身。结合了ORM
思想,是一个ORM
半自动的框架。 -
使用
Mybatis
之后,我们只需要定义一个Dao
层接口+存储SQL
的配置文件(Mybatis
映射配置文件),就可以完成Dao
层内容。
-
1. Mybatis
快速入门
1.1 Mybatis
快速入门步骤
-
导入Jar包
-
mybatis-3.5.3.jar
-
mysql-connector-java-5.1.37-bin.jar
-
log4j-1.2.17.jar
-
-
编写
Mybatis
核心配置文件:mybatis-config.xml
-
连接数据库四要素
-
<mapper>
标签中映射文件路径不是.
是/
建议复制,不要手敲
-
-
编写映射文件:
StudentDao.xml
-
编写
POJO
类和Dao
层接口,初始化数据库表及数据 -
SQL
-
实体类
-
接口
-
测试
-
小经验
-
直接生成
mybatis
的两类xml
文件 -
Mybatis
映射配置文件和接口之间相互跳转
-
核心配置文件
1 <?xml version="1.0" encoding="UTF-8" ?>
2 <!DOCTYPE configuration
3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
4 "http://mybatis.org/dtd/mybatis-3-config.dtd">
5 <configuration>
6 <environments default="development">
7 <environment id="development">
8 <transactionManager type="JDBC"/>
9 <dataSource type="POOLED">
10 <!-- 连接数据库四要素 -->
11 <property name="driver" value="com.mysql.jdbc.Driver"/>
12 <property name="url" value="jdbc:mysql:///web17_mybatis01"/>
13 <property name="username" value="root"/>
14 <property name="password" value="root"/>
15 </dataSource>
16 </environment>
17 </environments>
18
19
20 <!-- 加载映射配置文件 -->
21 <mappers>
22 <mapper resource="com/itheima/dao/StudentDao.xml"/>
23 </mappers>
24 </configuration>
映射配置文件
1 <?xml version="1.0" encoding="UTF-8" ?>
2 <!--
3 xml文档第一行是文档声明,必须在首行
4 接下来是:命名空间。作用如下:
5 1. 引入dtd文件
6 2. 对文档中标签及其属性进行约束
7 -->
8 <!DOCTYPE mapper
9 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
10 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
11
12 <!-- 把当前这个xml配置文件当做对应接口的实现类
13 通过namespace属性指向要被实现的接口,接口代理的方式必须这样写
14
15 -->
16 <mapper namespace="com.itheima.dao.StudentDao">
17 <!--
18 标签名:select 表示查询
19 id属性 id唯一标识,要配置被实现的接口中的方法
20 resultType属性 方法的结果(集合中泛型)的类型,全限定类名,不能省略
21 parameterType属性,方法发参数的类型,全限定类名,可以省略
22 标签体中书写SQL语句
23 整个标签被称之为:statement
24
25 -->
26 <select id="findById" resultType="com.itheima.domain.Student">
27 select * from student where id = 1;
28 </select>
29 </mapper>
接口StudentDao.java
1 public interface StudentDao {
2 Student findById();
3 }
测试类MybatisTest.java
2. API
2.1 Resources
读取配置的文件的工具类
InputStream getResourceAsStream
("配置文件相对于类路径的相对路径");
2.2 SqlSessionFactoryBuilder
获取SqlSessionFactory
工厂对象的功能类。
// 通过构建的方式构建了一个SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//xxxBuilder.build()
2.3 SqlSessionFactory
org.apache.ibatis.session.SqlSessionFactory
:获取 SqlSessi
对象的工厂接口。
SqlSession openSession()
获取SqlSession
对象,并开启手动提交事务
SqlSession openSession(boolean autoCommit)
获取SqlSession
对象,true
表示自动提交
2.4SqlSession
org.apache.ibatis.session.SqlSession
:sql会话对象接口。用于执行SQL
、管理事务、接口代理。
void | commit() | 提交事务 |
void | rollback() | 回滚事务 |
T | getMapper(Class cls) | 获取指定接口的代理实现类对象 |
void | close() | 释放资源 |
3. 映射配置文件
编码完成如下需求:
1 // 需求1:查询id为1的学生(强制要求) 2 // 需求2:创建一个Student对象并保存到数据库(参数和成员变量名保持一致)(成功了吗?) 3 // 需求3:根据学生姓名和年龄查询用户,传两个参数(多个参数怎么办?) 4 // 需求4:完成需求3,传一个参数。
映射配置文件StudentDao.xml
,保证这个文件的名字和接口名完全一致,且在同一个包下。
核心配置文件
1 <!-- 加载映射配置文件 这里使用的是/ --> 2 <mappers> 3 <mapper resource="com/itheima/dao/StudentDao.xml"/> 4 </mappers>
Dao
层接口StudentDao
1 public interface StudentDao {
2 @Select("select * from student where id = 1")
3 Student findById();
4
5 // 需求1:查询id为1的学生(强制要求)
6 Student findById2(@Param("id") Integer id);
7
8 // 需求2:创建一个Student对象并保存到数据库
9 void save(Student stu);
10
11 // 需求3:根据学生姓名和年龄查询用户,传两个参数(多个参数怎么办?)
12 List<Student> findByNameAndAge(@Param("name") String name, @Param("agex") Integer age);
13
14 // 需求4:完成需求3,传一个参数。
15 // 4.1 把两个参数封装成一个实体对象
16 // 如果把多个参数封装到一个实体对象中,参数类型有局限性,不能是两个一样的条件做范围查询
17 List<Student> findByStudent(Student stu);
18
19 // 4.2 把两个参数封装到Map集合中
20 List<Student> findByMap(Map<String,Object> map);
21 }
测试类
1 /**
2 * @Author sonyan
3 * @Date 2020/8/7 11:19
4 * @Description: 测试类
5 */
6 public class MybatisDemo {
7 public static void main(String[] args) throws Exception {
8
9 // 指定核心配置文件
10 String resource = "mybatis-config.xml";
11 // 把核心配置文件加载成流 Resources为我们提供的方便读取配置文件的工具类
12 InputStream inputStream = Resources.getResourceAsStream(resource);
13
14 // 通过构建的方式构建了一个SqlSessionFactory
15 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
16
17 // SqlSession 就相当于我们之前的 Connection
18 // JDK7新特性 try-with-resource
19 // 需要释放资源的动作,自动释放在try()中开启的一些流、会话......
20 try (SqlSession session = sqlSessionFactory.openSession(true)) {
21
22 // getMapper getDao 获取一个指定接口的实现类对象
23 // 底层是动态代理
24 // 动态代理可以增强有接口的类、接口(增强接口,就是现实接口)
25 // 就相当于我们自己new StudentDaoImpl();
26 // 这个StudentDaoImpl是Mybatis通过动态代理帮我们自动生成并且赋值给了studentDao
27 StudentDao studentDao = session.getMapper(StudentDao.class);
28
29 /*List<Student> students = studentDao.findAll();
30 System.out.println("students = " + students);*/
31
32
33 // 测试根据id查询
34 /*Student student = studentDao.findById(1);
35 System.out.println("student = " + student);*/
36
37 // 测试添加学生
38 //studentDao.saveStudent(new Student(null,"凤姐",20));
39
40 // 根据名称和年龄查询用户,参数是两个基本类型
41 //List<Student> students = studentDao.findByNameAndAge("美女", 20);
42 //System.out.println("students = " + students);
43
44 // 根据名称和年龄查询用户,参数是一个student对象
45 //List<Student> students = studentDao.findByUser(new Student(null, "凤姐", 20));
46 //System.out.println("students = " + students);
47
48 // 根据名称和年龄查询用户,参数是一个map集合
49
50 HashMap<String, Object> map = new HashMap<>();
51 map.put("name", "王二蛋");
52 map.put("age", 20);
53
54 System.out.println("studentDao.findByMap(map) = " + studentDao.findByMap(map));
55
56
57 // 手动提交
58 //session.commit();
59
60 // session.close();
61 }
62
63 }
64 }
4. 核心配置文件
4.1 properties(重要)
引入外部的properties文件,一般用作引入数据库链接参数的配置。
核心配置文件
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <!-- 这是一个mybatis的核心配置文件,名字任意--> 6 <configuration> 7 <!-- --> 8 <properties resource="jdbc.properties"/> 9 10 <environments default="development"> 11 <environment id="development"> 12 <transactionManager type="JDBC"/> 13 <dataSource type="POOLED"> 14 <property name="driver" value="${jdbc.driver}"/> 15 <property name="url" value="${jdbc.url}"/> 16 <property name="username" value="${jdbc.username}"/> 17 <property name="password" value="${jdbc.password}"/> 18 </dataSource> 19 </environment> 20 </environments> 21 22 <!-- 加载映射配置文件 --> 23 <mappers> 24 <mapper resource="com/itheima/dao/StudentDao.xml"/> 25 </mappers> 26 </configuration>
jdbc.properties
1 jdbc.driver=com.mysql.jdbc.Driver
2 jdbc.url=jdbc:mysql://192.168.115.130:3306/db1
3 jdbc.username=root
4 jdbc.password=root
4.2 Settings
(重要)
1 <!-- 极为重要的设置 --> 2 <settings> 3 <!-- 4 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 5 LOG4J 要求:1. 导入log4j的jar包 2. 有一个log4j.properties文件 6 建议显式的配置上。可配可不配的,建议配上。 7 --> 8 <setting name="logImpl" value="LOG4J"/> 9 10 11 <!-- 12 mapUnderscoreToCamelCase 13 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 14 15 Java中多个单词的属性名 使用驼峰命名 lastName 16 MySQL不缺分大小写 底杠命名 last_name 17 18 19 Mybatis可以帮我们自动完成结果集和实体的自动转换封装,原因是结果集的字段名和实体属性名一致。 20 21 --> 22 <!--<setting name="mapUnderscoreToCamelCase" value="true"/>--> 23 </settings>
4.3 TypeAliases
(了解)
1 <!-- 起别名 --> 2 <typeAliases> 3 <!-- 4 type 全限定类名 5 alias 别名 6 别名不区分大小写 7 --> 8 <!--<typeAlias type="com.itheima.domain.Student" alias="student"/>--> 9 10 <!-- 为包下所有的实体类起别名,不区分大小写 --> 11 <!--<package name="com.itheima.domain"/>--> 12 13 </typeAliases>
起别名后,在映射配置文件中可以直接使用别名
1 <select id="findByMap" resultType="Student">
2 select * from student where first_username=#{name}
3 and
4 age=#{age}
5 </select>
6
系统为常见的类型起好了别名
4.4 Environments
(了解)
1 <environments default="dev"> 2 <environment id="dev"> 3 <transactionManager type="JDBC"/> 4 <dataSource type="POOLED"> 5 <!-- 连接数据库四要素 --> 6 <property name="driver" value="${jdbc.driver}"/> 7 <property name="url" value="${jdbc.url}"/> 8 <property name="username" value="${jdbc.username}"/> 9 <property name="password" value="${jdbc.password}"/> 10 </dataSource> 11 </environment> 12 <environment id="test"> 13 <transactionManager type="JDBC"/> 14 <dataSource type="POOLED"> 15 <!-- 连接数据库四要素 --> 16 <property name="driver" value="${jdbc.driver}"/> 17 <property name="url" value="${jdbc.url}"/> 18 <property name="username" value="${jdbc.username}"/> 19 <property name="password" value="${jdbc.password}"/> 20 </dataSource> 21 </environment> 22 </environments>
4.5 Mappers
(重点)
1 <!-- 加载映射配置文件 --> 2 <mappers> 3 <!-- 4 使用相对于类路径的资源引用 可以用 5 每个标签引入一个Mapper的XML文件 6 --> 7 <!--<mapper resource="com/itheima/dao/StudentDao.xml"/>--> 8 <!--<mapper resource="com/itheima/dao/CourseDao.xml"/>--> 9 <!--<mapper resource="com/itheima/dao/OrderDao.xml"/>--> 10 11 <!-- 12 使用完全限定资源定位符(URL) 不推荐使用 13 http:// file:// 14 --> 15 <!--<mapper url="file:///var/mappers/AuthorMapper.xml"/>--> 16 17 <!-- 18 加载指定某个的接口,识别接口中的注解 可以用 19 --> 20 <!--<mapper class="com.itheima.dao.StudentDao"/>--> 21 <!--<mapper class="com.itheima.dao.StudentDao"/>--> 22 <!--<mapper class="com.itheima.dao.StudentDao"/>--> 23 24 <!-- 25 把包下所有的映射配置文件和接口全部加载进来 最推荐使用 26 --> 27 <package name="com.itheima.dao"/> 28 </mappers> 29
5. 经验分享
5.1 生成Mybatis
配置文件
本质是新建了一个文件模板,按照下面的方式新建两个模板即可(Mybatis-config
、Mybatis-Mapper
)
5.2 接口
和映射配置文件
跳转
使用一个插件free-idea-mybatis
。
这个插件是个zip包,不要解压,直接安装即可。
已知bug:
多个模块之间有相同内容会提示/跳转错误,卸载其他模块即可。
5.3 ${}和#{}区别(面试题)
##
{} MyBatis 会创建 PreparedStatement
参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法
${} 会做字符串的拼接,将{}中直接拼直接在 SQL 语句中,可能会有SQL注入的风险,效率更低。但是,如果你需要在SQL语句中直接插入一个不转义的字符串,可以使用这种方式。一般情况下会把表名或者字段名通过这方方式传递到SQL语句中,比方说 ORDER BY后面的列名。
5.4 MybatisUtils工具类抽取
1 public class MybatisUtills {
2
3 // 获取工厂对象SQLSessionFactory,这个对象一个就可
4 private static SqlSessionFactory ssf = null;
5
6 // 静态代码块中初始化该对象
7 static {
8 InputStream is = null;
9 try {
10 is = Resources.getResourceAsStream("MyBatisConfig.xml");
11 } catch (IOException e) {
12 e.printStackTrace();
13 }
14 ssf = new SqlSessionFactoryBuilder().build(is);
15 }
16
17 public static SqlSessionFactory getFactory() {
18 return ssf;
19 }
20
21
22 // 获取SQLSession对象,这个连接对象可以有多个
23 public static SqlSession getSqlSession() {
24 return ssf.openSession(true);
25 }
26
27
28 // 获取Mapper对象
29 public static <T> T getMapper(Class<T> tClass) {
30 return ssf.openSession(true).getMapper(tClass);
31 }
32
33 }