前言
项目框架中 mybatis用于数据访问层
界面层:servlet--springmvc
业务逻辑层:service类--spring
数据访问层:dao类--mybatis
三层的访问交互是依次进行 在深入访问数据库后依次退出
==了解更多mybatis 可查看==
mybatis入门中文文档
该文章的学习主要通过视频进行总结汇总
2020最新MyBatis教程【IDEA版】-MyBatis从入门到精通
该文章的学习代码如下
mybatis从入门到精通的学习代码.rar
1. idea软件小技巧
- ctrl+alt+shift+c 复制全限定名称 相当于copy reference
- ctrl+shift+o 相当于reimport
- 创建类文件 =包名.类名 会自动生成包与类
- 无法创建xml文件,可以直接创建普通文件,名字后缀加xml
- 代码变红色,引入class包名,alt+enter
2. mybatis优势
==而mybatis框架的好处对比==
mybatis与jdbc、hibernate的对比:
jdbc:代码比较多,开发效率低,重复代码多,业务代码和数据库操作混杂一起。在代码块中对象要创建和销毁,查询的结果要封装list。
hibernate:全自动
mybatis:提供访问数据库基本功能,半自动,sql与java编码分离,轻量级的框架
回顾jdbc的代码可看我之前的文章
jdbc从入门到精通(全)
学完之后,发现jdbc的代码
- 业务代码和数据库的操作混在一起
- 重复的代码比较多
为此减轻使用 JDBC 的复杂性,不用编写重复的创建 Connetion , Statement ; 不用编写关闭资源代码。直接使用 java 对象,表示结果数据。让开发者专注 SQL 的处理。 其他分心的工作由 MyBatis 代劳
mybatis两大功能:
- sql mapper:sql映射,可以把数据库表中的一行数据,映射为一个java对象,操作此对象即操作此数据
- dao类:数据访问,进行数据增删改查
写sql即可,不必关心Connection,Statement,ResultSet的创建,销毁,sql的执行
- MyBatis 是一个优秀的基于 java 的持久层框架,内部封装了 jdbc,开发者只需要关注 sql 语句本身,而不需要处理加载驱动、创建连接、创建statement、关闭连接,资源等繁杂的过程。
- MyBatis 通过 xml 或注解两种方式将要执行的各种 sql 语句配置起来,并通过 java 对象和 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。
3. mybatis入门项目
3.1 项目具体步骤
这个具体步骤比较重要
可以边建立项目的时候边想代码是如何调用
- 新建数据表
- maven配置以及在pom.xml中加入mybatis坐标和mysql驱动依赖 还有xml的生成配置(因为类路径下不会自动生成)
- 创建类,保存表中的数据
- 创建dao接口,定义操作数据库方法接口方法。
- 创建mapper文件,即在同一目录下定义sql映射文件,写sql文件和接口方法对应的sql语句
- 创建mybatis主配置文件(提供数据库连接信息和xml中sql的映射信息(指定mapper文件的位置),也就是类路径的具体位置。
- 创建mybatis类(SqlSession对象),来访问数据库sql
3.2 创建数据表
将java与数据库连接
涉及数据库可看我上一篇文章
数据库中增删改常用语法语句(全)
数据库查询常用语句语法
CREATE TABLE `student` (
`id` int(11) NOT NULL ,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
AI 代码解读
3.3 创建maven项目
项目启用maven,具体配置可查看我上一篇文章
Maven详细配置(全)
项目启动成功后截图 出现build success
3.4 pom.xml配置文件
- 坐标、mybatis依赖和mysql驱动
- 扫描的xml插件、编译器版本和单元测试
<!--坐标 -->
<groupId>org.example</groupId>
<artifactId>mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<!--配置该有的编译器版本,此版本为1.8 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<!--单元测试 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--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>5.1.9</version>
</dependency>
</dependencies>
AI 代码解读
还要添加一个xml的配置文件
因为java默认文件路径识别不到xml的后缀
之后再target下才会生成
<!--扫描xml插件 -->
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
AI 代码解读
配置好之后ctrl+shift+o更新配置或者是右键在maven中 reimport
3.5 数据类、接口类和映射文件
创建一个数据类,包含数据的定义,设值以及获取等
//推荐和表名一样。容易记忆
public class Student {
//定义属性, 目前要求是属性名和列名一样。
private Integer id;
private String name;
private String email;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
AI 代码解读
创建另一个包,包含接口类和配置文件
创建一个包含所有数据的列表,每个数据就是一个对象
用该方法来调用数据
//查询student表的所有的数据
public List<Student> selectStudents();
AI 代码解读
而这个数据要用在该类中同一目录之中,同一包之下的xml文件
==mybatis会执行这些sql文件,具体格式代码说明:==
1.dtd为约束文件,限制和检查出现的标签是否符合mybatis定义的规则
2.mapper为根标签,namespace为命名空间,可以自定义的字符串,最好用dao接口全限定名称
3.使用特定标签表示数据库特定操作
~select查询,update更新,insert插入,delete删除
~3.1 内部名称为 id是sql的唯一标识,mybatis会通过id值执行sql语句,可以任意定值,但最好用接口中方法的名称调用
~3.2 resultType为结果类型,执行sql后得到resultSet,并且遍历它所得到java对象类型。==类比jdbc的创建数据集==即执行的sql数据得到的结果,最后一一赋给java对象获取,最好用全限定名称,也就是实体类的全限定名称
总结:
- dao接口全限定名称用在mapper的根标签
- id为方法名
- resultType为返回的实体类对象全限定名称
==namespace为接口名,id为方法名,resultType为定义的类名==
==后面定义的测试类中 执行数据库语句的字符串即为接口名.方法名==
<?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.bjpowernode.dao.StudentDao">
<!--
select:表示查询操作。
id: 你要执行的sql语法的唯一标识, mybatis会使用这个id的值来找到要执行的sql语句
可以自定义,但是要求你使用接口中的方法名称。
resultType:表示结果类型的, 是sql语句执行后得到ResultSet,遍历这个ResultSet得到java对象的类型。
值写的类型的全限定名称
-->
<select id="selectStudents" resultType="com.bjpowernode.domain.Student" >
select id,name,email,age from student order by id
</select>
</mapper>
AI 代码解读
==总之id用列表定义的方法名,namespace和resultType用全限定名称路径名==
3.6 mybatis主配置文件
这个主配置文件和jdbc文件中的这个代码功能一致
新建一个resources目录并且设置改目录为resources root
在该目录下新建一个mybatis.xml的配置文件
- dtd约束文件名称
- configuration根标签
- environments 环境配置为连接数据库的信息,default需要与environment某个id值一样,表示需要使用哪个数据库信息
- environment 数据库配置信息,id唯一值 表示环境名称
- transactionManager为mybatis的事务类型
- dataSource表示数据源,连接数据库
主要看代码中的注释也可以
==数据库连接信息==
<environments default="mydev">
<!-- environment : 一个数据库信息的配置, 环境
id:一个唯一值,自定义,表示环境的名称。
-->
<environment id="mydev">
<!--
transactionManager :mybatis的事务类型
type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示数据源,连接数据库的
type:表示数据源的类型, POOLED表示使用连接池
-->
<dataSource type="POOLED">
<!--
driver, user, username, password 是固定的,不能自定义。
-->
<!--数据库的驱动类名-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--连接数据库的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<!--访问数据库的用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="123456"/>
</dataSource>
</environment>
AI 代码解读
==sql映射mapper位置==
一个mapper标签指定一个文件位置,可以用多个mapper标签指定
==这个文件位置间隔需要用 /==
点击maven的compile编译即可
上面的pom.xml配置了识别xml配置文件
会在target/clasess(类路径)下生成
具体调用的映射文件的位置(通过target/clasess(类路径))要通过mapper进行映射
<!-- sql mapper(sql映射文件)的位置-->
<mappers>
<!--一个mapper标签指定一个文件的位置。
从类路径开始的路径信息。 target/clasess(类路径)
-->
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
<!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
</mappers>
AI 代码解读
==做项目整合的时候只需要修改
数据库的连接信息以及sql映射位置即可
其他都雷同,只需修改此处两个位置==
3.7 测试文件
在生成的/target/class下有xml配置文件路径
(class文件中必须要有主配置文件)
- 用sql的SqlSessionFactory对象调用读取的主配置文件
- 以此来打开session文件,赋值给SqlSessionFactoryBuilder对象
- 通过sql文件映射的执行语句输出结果
具体怎么识别是哪个xml配置文件
主要通过xml配置文件中的namespace的命名空间
com.bjpowernode.dao.StudentDao(为全限定名称名)+selectStudents(方法名)
最后为com.bjpowernode.dao.StudentDao.selectStudents
public static void main(String[] args) throws IOException {
//访问mybatis读取student数据
//1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess)
String config="mybatis.xml";
//2.读取这个config表示的文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建了SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4.创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
//5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
SqlSession sqlSession = factory.openSession();
//6.【重要】指定要执行的sql语句的标识。 sql映射文件中的namespace + "." + 标签的id值
//String sqlId = "com.bjpowernode.dao.StudentDao" + "." + "selectStudents";
//namespace.id值为sqlId的执行语句
String sqlId = "com.bjpowernode.dao.StudentDao.selectStudents";
//7. 重要】执行sql语句,通过sqlId找到语句
List<Student> studentList = sqlSession.selectList(sqlId);
//8.输出结果
//studentList.forEach( stu -> System.out.println(stu));
for(Student stu : studentList){
System.out.println("查询的学生="+stu);
}
//9.关闭SqlSession对象
sqlSession.close();
}
AI 代码解读
运行的即种解决方法:
- maven插件的 clean->compile
- 窗口中build的rebuild project
- 窗口中file的Invalidate Caches
- 手工拷贝复制target不存在的文件
在编译过程中如果出现以下问题
可查看我之前的文章
- 出现Could not find resource mybatis.xml的解决方法
- 出现target\surefire-reports for the individual test results的解决方法
编译成功之后的数据展示台如下
配合数据库表可一一验证
3.8 dubug代码
- ==定义一个配置文件之后直接获取配置文件==
进入到直接获取配置文件的源码,直接获取
return返回另一个代码函数
在调用另外一个函数,也就是类加载器
一直遍历判断直到他是为止
- ==用sql的SqlSessionFactory对象调用读取的主配置文件==
具体源码内部如下
- ==以此来打开session文件,赋值给SqlSessionFactoryBuilder对象==
3.9 配置文件模板
1.映射文件模板
<?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="接口包名全名称">
<select id=" 方法名" resultType="含数据的类名全名称">
</select>
</mapper>
AI 代码解读
2.主配置文件
<?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>
<!--settings:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="mydev">
<environment id="mydev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED"> <!--数据库连接池-->
<!--数据库的驱动类名-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--连接数据库的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<!--访问数据库的用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- sql mapper(sql映射文件)的位置-->
<mappers>
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
<!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
</mappers>
</configuration>
AI 代码解读
idea具体设置位置:
3.10 功能添加-插入元素
基于以上项目进行整改
添加额外的插入数据库元素的功能
数据库的增删改查,原本有查询功能,现在额外补充一个插入元素功能
1.接口类中补充插入元素的方法
插入的元素为类对象,返回结果为数据行数,即int类型
//插入方法
//参数: student ,表示要插入到数据库的数据
//返回值: int , 表示执行insert操作后的 影响数据库的行数
public int insertStudent(Student student);
AI 代码解读
2.与接口类中同一目录下的sql映射文件xml中 添加一个插入元素
id最好用插入方法类
插入的具体格式是 #{ }
,没有返回的实体类类型,所以不用resultType这个属性
<!--插入操作-->
<insert id="insertStudent">
insert into student values(#{id},#{name},#{email},#{age})
</insert>
AI 代码解读
以上两个文件的具体位置如下
3.测试类中额外几个函数
//6.【重要】指定要执行的sql语句的标识。 sql映射文件中的namespace + "." + 标签的id值
String sqlId = "com.bjpowernode.dao.StudentDao.insertStudent";
//7. 重要】执行sql语句,通过sqlId找到语句
Student student = new Student();
student.setId(1006);
student.setName("关羽");
student.setEmail("guanyu@163.com");
student.setAge(20);
int nums = sqlSession.insert(sqlId,student);
//mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
//sqlSession.commit();
AI 代码解读
添加代码主要通过sqlSession这个类中的函数
这个函数源码是
==第一个为sql语句,第二个为对象参数==
完整代码如下:
public class TestMyBatis {
//测试方法,测试功能
@Test
public void testInsert() throws IOException {
//访问mybatis读取student数据
//1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess)
String config="mybatis.xml";
//2.读取这个config表示的文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建了SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4.创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
//5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
SqlSession sqlSession = factory.openSession();
//SqlSession sqlSession = factory.openSession(true);
//6.【重要】指定要执行的sql语句的标识。 sql映射文件中的namespace + "." + 标签的id值
String sqlId = "com.bjpowernode.dao.StudentDao.insertStudent";
//7. 重要】执行sql语句,通过sqlId找到语句
Student student = new Student();
student.setId(1006);
student.setName("关羽");
student.setEmail("guanyu@163.com");
student.setAge(20);
int nums = sqlSession.insert(sqlId,student);
//mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
sqlSession.commit();
//8.输出结果
System.out.println("执行insert的结果="+nums);
//9.关闭SqlSession对象
sqlSession.close();
}
}
AI 代码解读
编译完成之后,需要提交事务才可看到新增加的数据,mybatis默认是没有提交事务
即在insert ,update ,delete后要手工提交事务
//mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
sqlSession.commit();
AI 代码解读
insert ,update ,delete这些数据在编译器的输出平台中看不到
需要添加一个日志才可看到
具体日志的配置在下面
具体显示结果如下(添加了日志)
查看其数据库的结果如下
具体可看我这篇文章
添加数据到数据库中显示乱码的解决方法
3.11 日志提交
需要在mybatis.xml主配置文件中添加一个日志
才会在编译器看到修改数据库的结果
<!--settings:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
AI 代码解读
4. 改进步骤
4.1 常用类介绍
介绍如何改进的时候
先介绍下常用类的代码逻辑
//访问mybatis读取student数据
//1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess)
String config="mybatis.xml";
//2.读取这个config表示的文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建了SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4.创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
//5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
//SqlSession sqlSession = factory.openSession();
SqlSession sqlSession = factory.openSession(true);
//6.【重要】指定要执行的sql语句的标识。 sql映射文件中的namespace + "." + 标签的id值
String sqlId = "com.bjpowernode.dao.StudentDao.insertStudent";
//7. 重要】执行sql语句,通过sqlId找到语句
Student student = new Student();
student.setId(1006);
student.setName("关羽");
student.setEmail("guanyu@163.com");
student.setAge(20);
int nums = sqlSession.insert(sqlId,student);
//mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
sqlSession.commit();
//8.输出结果
System.out.println("执行insert的结果="+nums);
//9.关闭SqlSession对象
sqlSession.close();
AI 代码解读
主要是介绍上面这些方法中的具体步骤以及使用过程
- 1. Resources:读取主配置文件,是mybatis的一个类
InputStream in = Resources.getResourceAsStream("mybatis.xml");
AI 代码解读
- 2. SqlSessionFactoryBuilder : 创建SqlSessionFactory对象
主要的过程是先创建自我的实体类对象,之后通过自我实体类对象创建一个SqlSessionFactory对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
AI 代码解读
总体来说就是
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
AI 代码解读
- 3.SqlSessionFactory :接口类,整个项目有一个此对象即可
获取SqlSession对象,SqlSession sqlSession = factory.openSession();
openSession() :无参数, 非自动提交事务SqlSession
openSession(true) : 自动提交事务的SqlSession
openSession(false) 非自动提交事务的SqlSession
即在接口类这样定义即可
//5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
SqlSession sqlSession = factory.openSession(true);
AI 代码解读
==上下两条语句对等==
//5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
SqlSession sqlSession = factory.openSession();
//mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
sqlSession.commit();
//或者直接写
SqlSession sqlSession = factory.openSession(true);
AI 代码解读
- ==4.SqlSession接口 :定义了操作数据的方法==
有selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()等
SqlSession对象不是线程安全的,即执行sql语句之前,使用openSession()获取SqlSession对象。执行结束后关闭SqlSession.close()
,这样才是安全的
SqlSession的实现类是DefaultSqlSession,都重写了这些方法,主要是多态的一个使用方法
4.2 封装工具类
将常用类进行封装
大部分都是一样的
public class MyBatisUtils {
private static SqlSessionFactory factory = null;
static {
String config="mybatis.xml"; // 需要和你的项目中的文件名一样
try {
InputStream in = Resources.getResourceAsStream(config);
//创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession的方法
public static SqlSession getSqlSession() {
SqlSession sqlSession = null;
if( factory != null){
sqlSession = factory.openSession();// 非自动提交事务
}
return sqlSession;
}
}
AI 代码解读
在测试类的完整代码如下:
public class MyApp2 {
public static void main(String[] args) throws IOException {
//获取SqlSession对象,从SqlSessionFactory中获取SqlSession
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//【重要】指定要执行的sql语句的标识。 sql映射文件中的namespace + "." + 标签的id值
String sqlId = "com.bjpowernode.dao.StudentDao.selectStudents";
//【重要】执行sql语句,通过sqlId找到语句
List<Student> studentList = sqlSession.selectList(sqlId);
//输出结果
studentList.forEach( stu -> System.out.println(stu));
//关闭SqlSession对象
sqlSession.close();
}
}
AI 代码解读
4.3 传统dao类改进
本身
StudentDao类很少用到,主要还是用到了sqlsession的方法,StudentDao类主要是做一个指引的指示
为了封装更好的使用重写这个类的方法
主要区别在于改写接口类的方法,以便在测试类中直接定义,和传统写法保持一致,定义的接口和测试类分隔开
获取数据库,执行sql语句,在测试类进行书写
public class StudentDaoImpl implements StudentDao {
@Override
public List<Student> selectStudents() {
//获取SqlSession对象
//通过封装类进行执行
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//主要是这个sql语句
String sqlId="com.bjpowernode.dao.StudentDao.selectStudents";
//执行sql语句, 使用SqlSession类的方法
List<Student> students = sqlSession.selectList(sqlId);
//关闭
sqlSession.close();
return students;
}
@Override
public int insertStudent(Student student) {
//获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
String sqlId="com.bjpowernode.dao.StudentDao.insertStudent";
//执行sql语句, 使用SqlSession类的方法
int nums = sqlSession.insert(sqlId,student);
//提交事务
sqlSession.commit();
//关闭
sqlSession.close();
return nums;
}
}
AI 代码解读
测试类的定义
通过调用执行类
在调用执行类的方法
public class TestMyBatis {
@Test
public void testSelectStudents(){
//com.bjpowernode.dao.StudentDao
StudentDao dao = new StudentDaoImpl();
List<Student> studentList = dao.selectStudents();
for(Student stu:studentList){
System.out.println(stu);
}
}
@Test
public void testInsertStudent(){
StudentDao dao = new StudentDaoImpl();
Student student = new Student();
student.setId(1005);
student.setName("盾山");
student.setEmail("dunshan@qq.com");
int nums = dao.insertStudent(student);
System.out.println("添加对象的数量:"+nums);
}
}
AI 代码解读
==通过以上改写接口类和测试类的代码中,可以看到很多冗余一样的代码,只不过几处不一样而已,其实还可以继续封装==
5. 动态代理
关于这部分知识涉及到了jdk的动态代理
可看我之前的文章进行了解
jdk动态代理(AOP)从入门到精通(全)
xml文件定义如下
通过调用执行类来执行xml下的sql文件(也就是映射对象)
StudentDao dao = new StudentDaoImpl();
这个语句调用dao对象,类型是StudentDao,全限定名称是:com.bjpowernode.dao.StudentDao,全限定名称 和 namespace 是一样的。List<Student> studentList = dao.selectStudents();
通过dao中方法的返回值也可以确定MyBatis要调用的SqlSession的方法,也就是查看xml配置文件中的定义
如果返回值是List ,调用的是SqlSession.selectList()方法
如果返回值 int ,或是非List的,看mapper文件中的标签是<insert>,<update> 就会调用SqlSession的insert, update等方法
==以此引出动态代理的结构,节省代码量,也就是测试类可以不用这么冗余,也不用定义实现类==
- mybatis根据 dao的方法调用,获取执行sql语句的信息
- mybatis根据dao接口,创建dao接口的实现类, 并创建该类的对象,完成SqlSession调用方法, 访问数据库
具体如何创建如何执行
==使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口),getMapper能获取dao接口对于的实现类对象==
mybatis内部通过接口名和方法名映射到对应xml文件中的sql语句执行
将其上面的测试类和实现类合并变成一个
直接调用封装类
具体如下
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//通过动态代理得到其类的对象
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//com.sun.proxy.$Proxy2 : jdk的动态代理
System.out.println("dao="+dao.getClass().getName());
//调用dao的方法, 执行数据库的操作
List<Student> students = dao.selectStudents();
for(Student stu: students){
System.out.println("学生="+stu);
}
AI 代码解读
以及添加的测试代码如下
@Test
public void testInsertStudent(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setId(1007);
student.setName("李飞");
student.setEmail("dunshan@qq.com");
student.setAge(28);
int nums = dao.insertStudent(student);
sqlSession.commit();
System.out.println("添加对象的数量:"+nums);
}
AI 代码解读
5.1 参数剖析
==parameterType==
此处也是重点讲解一个参数该如何使用
接口中方法参数的类型, 类型的完全限定名或别名
例如:parameterType="java.lang.Integer"parameterType="int"
AI 代码解读- parameterType不是强制的,mybatis通过反射机制能够发现接口参数的数类型,可以没有,一般不写
主要写在dao.xml的配置文件下
<select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where id=${id}
</select>
AI 代码解读
或者是
<select id="selectStudentById" parameterType="int" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where id=${id}
</select>
AI 代码解读
5.2 深入理解参数
5.2.1 单参数
主要写在dao.xml的配置文件下
<select id="selectStudentById" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where id=${id}
</select>
AI 代码解读
具体接口类的定义如下
public Student selectStudentById(Integer id)
AI 代码解读
使用#{}
之后, mybatis执行sql是使用的jdbc中的PreparedStatement
对象
由mybatis执行下面的代码:
- mybatis创建Connection , PreparedStatement对象
String sql="select id,name, email,age from student where id=?";
PreparedStatement pst = conn.preparedStatement(sql);
pst.setInt(1,1001);
AI 代码解读
- 执行sql封装为resultType="com.bjpowernode.domain.Student"这个对象
ResultSet rs = ps.executeQuery();
Student student = null;
while(rs.next()){
//从数据库取表的一行数据, 存到一个java对象属性中
student = new Student();
student.setId(rs.getInt("id));
student.setName(rs.getString("name"));
student.setEmail(rs.getString("email"));
student.setAge(rs.getInt("age"));
}
return student; //给了dao方法调用的返回值
AI 代码解读
5.2.2 多参数
==@Param==
多个参数: 命名参数,在形参定义的前面加入 @Param("自定义参数名称")
xml文件的定义
<!--多个参数,使用@Param命名-->
<select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where name=#{myname} or age=#{myage}
</select>
AI 代码解读
dao类接口的定义
List<Student> selectMultiParam(@Param("myname") String name,
@Param("myage") Integer age);
AI 代码解读
具体测试类的书写如下
@Test
public void testSelectMultiParam(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectMultiParam("李四",20);
for(Student stu: students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
AI 代码解读
==使用对象==
使用java对象作为接口中方法的参数
List<Student> selectMultiStudent(Student student);
AI 代码解读
使用java对象的属性值,作为参数实际值
使用对象语法: #{属性名,javaType=类型名称,jdbcType=数据类型}
很少用。
- javaType:指java中的属性数据类型。
- jdbcType:在数据库中的数据类型。
例如: #{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
我们使用的简化方式: #{属性名} ,javaType, jdbcType的值mybatis反射能获取。不用提供
很少使用
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where
name=#{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
or age=#{paramAge,javaType=java.lang.Integer,jdbcType=INTEGER}
</select>
AI 代码解读
一般这样使用
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where
name=#{paramName} or age=#{paramAge}
</select>
AI 代码解读
测试类的代码
@Test
public void testSelectMultiStudent(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setName("张三");
student.setAge(28);
List<Student> students = dao.selectMultiStudent(student);
for(Student stu: students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
AI 代码解读
==按照位置==
不推荐,不是很灵活
- mybatis.3.4之前,使用
#{0} ,#{1}
- mybatis。3.4之后 ,使用
#{arg0} ,#{arg1}
List<Student> selectMultiPosition( String name,Integer age);
AI 代码解读
xml文件的定义
<select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where
name = #{arg0} or age=#{arg1}
</select>
AI 代码解读
直接在测试类的时候一一对应进行输入
@Test
public void testSelectMultiPosition(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectMultiPosition("李四",20);
for(Student stu: students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
AI 代码解读
==多个参数,使用Map存放多个值==
不推荐,不是很灵活
List<Student> selectMultiByMap(Map<String,Object> map);
AI 代码解读
xml文件的配置
<select id="selectMultiByMap" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where
name = #{myname} or age=#{age1}
</select>
AI 代码解读
通过放置一个key值进行一一相应
@Test
public void testSelectMultiByMap(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Map<String,Object> data = new HashMap<>();
data.put("myname","张三");
data.put("age1",28);
List<Student> students = dao.selectMultiByMap(data);
for(Student stu: students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
AI 代码解读
5.2.3 占位符
关于占位符的知识点,可看我之前的文章补充
jdbc之问号占位符的详细分析
对比一下两个占位符#
和 $
- # 的占位符
select id,name, email,age from student where id = #{id}
AI 代码解读
最后的结果是 select id,name, email,age from student where id =?
- $ 的占位符
select id,name, email,age from student where id = ${id}
AI 代码解读
最后的结果是 select id,name, email,age from student where id =1001
$这个占位符使用的是字符串的拼接
使用的是statement对象执行sql,效率比PreparedStatement要低- $可以替换表名或者列名,如果确定数据安全可以使用这个
具体两者的区别
- # 使用?占位符,使用的是PreparedStatement执行sql,效率高,避免了sql注入,更加安全
- $ 不使用?占位符,使用字符串连接,statement对象执行sql,效率低。有sql注入风险,安全性低。可以替换表名或者列名
==所谓的替换列名是这个意思==
List<Student> selectUse$Order(@Param("colName") String colName);
AI 代码解读
xml文件定义如下
<select id="selectUse$Order" resultType="com.bjpowernode.domain.Student">
select * from student order by ${colName}
</select>
AI 代码解读
测试代码如下
@Test
public void testSelectUse$Order(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectUse$Order("age");
for(Student stu: students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
AI 代码解读
==所谓的数据安全与否==
因为是字符串的拼接
所以如果语句结构是这样dao.selectUse$("'李四';select * from user");
引入字符串''
,内容是sql语句,可以实现sql注入修改后台数据,造成数据不安全
5.2.4 总结
回顾一下之前的知识点
大致如下
动态代理:mybatis创建dao接口的实现类,在实现类中调用sqlsession方法执行sql语句
getmapper创建对象的时候本身就是一个jdk动态代理方式
com.sun.proxy.$Proxy2 : jdk的动态代理
之后获取到sqlsession的执行方法,获取其sql语句结构
使用动态代理的方式:
- 获取sqlsession对象
- 使用getmapper方法获取接口对象
- 调用接口方法,执行mapper文件的sql语句
通过debug 剖析其源码
部分截图如下
具体getmapper
5.3 封装mybatis输出结果
5.3.1 resultType
mybatis执行了sql语句,得到java对象
具体执行的思路是
mybatis执行sql语句, 然后mybatis调用类的无参数构造方法,创建对象
mybatis把ResultSet指定列值付给同名的属性
<select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student
</select>
AI 代码解读
在对等的jdbc时
分别通过setId进行配对
ResultSet rs = executeQuery(" select id,name, email,age from student" )
while(rs.next()){
Student student = new Student();
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"))
}
AI 代码解读
- 简单类型
<!--sql执行后返回一行一列-->
<!--<select id="countStudent" resultType="int">-->
<select id="countStudent" resultType="java.lang.Integer">
select count(*) from student
</select>
AI 代码解读
- 对象类型
List<Student> selectMultiParam(@Param("myname") String name,
@Param("myage") Integer age);
AI 代码解读
<!--多个参数,使用@Param命名-->
<select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where name=#{myname} or age=#{myage}
</select>
AI 代码解读
- map类型
==只能最多返回一行记录。多余一行是错误==
//定义方法返回Map
Map<Object,Object> selectMapById(Integer id);
AI 代码解读
<!--返回Map
1)列名是map的key, 列值是map的value
2)只能最多返回一行记录。多余一行是错误
-->
<select id="selectMapById" resultType="java.util.HashMap">
select id,name,email from student where id=#{stuid}
</select>
AI 代码解读
具体测试文件如下
//返回Map
@Test
public void testSelecMap(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Map<Object,Object> map = dao.selectMapById(1001);
System.out.println("map=="+map);
}
AI 代码解读
5.3.2 别名
再mybatis.xml配置文件中定义别名的配置
之后就可以直接使用自已定义的实体类的全限定名称的别名
第一种方式(可读性很差,很少使用)
可以指定一个类型一个自定义别名
- type:自定义类型的全限定名称
- alias:别名
<typeAliases>
<typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
<typeAlias type="com.bjpowernode.vo.ViewStudent" alias="vstu" />
</typeAliases>
AI 代码解读
第二种方式(很少使用,会出错)
<package>
name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)
<!--定义别名-->
<typeAliases>
<package name="com.bjpowernode.domain"/>
<package name="com.bjpowernode.vo"/>
</typeAliases>
AI 代码解读
最后的类名就是别名
最后一种别名的格式很少使用
因为如果在同一个文件中定义有两个同名类,会不知道引用哪个
5.3.3 resultMap
可以定义多行数据
使用resultMap定义映射关系
List<Student> selectAllStudents();
AI 代码解读
xml文件的定义
将其property=column 这样赋值
<!--定义resultMap
id:自定义名称,表示你定义的这个resultMap
type:java类型的全限定名称
-->
<resultMap id="studentMap" type="com.bjpowernode.domain.Student">
<!--列名和java属性的关系-->
<!--注解列,使用id标签
column :列名
property:java类型的属性名
-->
<id column="id" property="id" />
<!--非主键列,使用result-->
<result column="name" property="name" />
<result column="email" property="email" />
<result column="age" property="age" />
</resultMap>
<select id="selectAllStudents" resultMap="studentMap">
select id,name, email , age from student
</select>
AI 代码解读
具体测试类的定义如下
@Test
public void testSelectAllStudents(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectAllStudents();
for(Student stu: students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
AI 代码解读
==property 要与实体类的定义一样
而column 要与select 的定义一样==
第二种方式是
使用resultType的属性,之后再定义的时候通过
数据库名 id查询 映射到实体类中的的结果 进行辨别
或者直接在数据库中修改别名,和实体类一致就可以使用
<!--列名和属性名不一样:第二种方式
resultType的默认原则是 同名的列值赋值给同名的属性, 使用列别名(java对象的属性名)
-->
<select id="selectDiffColProperty" resultType="com.bjpowernode.domain.MyStudent">
select id as stuid ,name as stuname, email as stuemail , age stuage from student
</select>
AI 代码解读
5.4 模糊like
==第一种模糊查询, 在java代码指定 like的内容==
List<Student> selectLikeOne(String name);
AI 代码解读
<!--第一种 like , java代码指定 like的内容-->
<select id="selectLikeOne" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name like #{name}
</select>
AI 代码解读
测试类的代码如下
@Test
public void testSelectLikeOne(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//准备好like的内容
String name = "%李%";
List<Student> students = dao.selectLikeOne(name);
for(Student stu: students){
System.out.println("#######学生="+stu);
}
sqlSession.close();
}
AI 代码解读
==name就是李值, 在mapper中拼接 like "%" 李 "%" ==
List<Student> selectLikeTwo(String name);
AI 代码解读
这种方式 "%" #{name} "%"
中间一定要带空格
<!--第二种方式:在mapper文件中拼接 like的内容-->
<select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name like "%" #{name} "%"
</select>
AI 代码解读
测试类的代码如下
@Test
public void testSelectLikeTwo(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//准备好like的内容
String name = "张";
List<Student> students = dao.selectLikeTwo(name);
for(Student stu: students){
System.out.println("*******学生="+stu);
}
sqlSession.close();
}
AI 代码解读
6. 动态sql
6.1 if结构
<if>是判断条件的,
语法<if test="判断java对象的属性值">
部分sql语句
</if>
AI 代码解读
<if:test="使用参数java对象的属性值作为判断条件,语法 属性=XXX值">
//动态sql ,使用java对象作为参数
List<Student> selectStudentIf(Student student);
AI 代码解读
<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
select id,name, age, email from student
where
<if test="name !=null and name !='' ">
name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</select>
AI 代码解读
测试代码如下
@Test
public void testSelectStudentIf(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setName("李四");
student.setAge(20);
List<Student> students = dao.selectStudentIf(student);
for(Student stu:students){
System.out.println("if==="+stu);
}
AI 代码解读
但是这种写法有缺陷
如果第一个if不满足了,第二个if 前面会带一个or结构 变成where or 就不对了
为了避免这种规则
可以这样书写xml文件
在前面的条件加上恒等式或者本身属性就会成立的条件
where 1=1
<if test="name !=null and name !='' ">
and name = #{name}
AI 代码解读
6.2 where结构
当多个if有一个成立的, <where>
会自动增加一个where关键字,并去掉 if中多余的 and ,or等
//where使用
List<Student> selectStudentWhere(Student student);
AI 代码解读
where: <where> <if> <if>...</where>
AI 代码解读
<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
select id,name, age, email from student
<where>
<if test="name !=null and name !='' ">
name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</where>
</select>
AI 代码解读
也就是当其中一个if条件成立的时候 就会有where,如果都没成立,就没有where
成立的时候还会去掉前面的多余的 or 或者and
6.3 foreach结构
==添加常用的类型结构==
- collection:表示接口中的方法参数的类型, 如果是数组使用array , 如果是list集合使用list
- item:自定义的,表示数组和集合成员的变量
- open:循环开始是的字符
- close:循环结束时的字符
- separator:集合成员之间的分隔符
//foreach 用法 1
List<Student> selectForeachOne(List<Integer> idlist);
AI 代码解读
<!--foreach使用1 , List<Integer>-->
<select id="selectForeachOne" resultType="com.bjpowernode.domain.Student">
select * from student where id in
<foreach collection="list" item="myid" open="(" close=")" separator=",">
#{myid}
</foreach>
</select>
AI 代码解读
具体拼接测试代码如下
- 添加列表
- 用builder来遍历添加列表的值
==重要代码的逻辑思路==
@Test
public void testfor(){
List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
//String sql="select * from student where id in (1001,1002,1003)";
String sql="select * from student where id in";
StringBuilder builder = new StringBuilder("");
int init=0;
int len = list.size();
//添加开始的 (
builder.append("(");
for(Integer i:list){
builder.append(i).append(",");
}
builder.deleteCharAt(builder.length()-1);
//循环结尾
builder.append(")");
sql = sql + builder.toString();
System.out.println("sql=="+sql);
}
AI 代码解读
这种思路在leetcode中的列表拼接很常用
添加对象为类型
//foreach 用法 2
List<Student> selectForeachTwo(List<Student> stulist);
AI 代码解读
<select id="selectForeachTwo" resultType="com.bjpowernode.domain.Student">
select * from student where id in
<foreach collection="list" item="stu" open="(" close=")" separator=",">
#{stu.id}
</foreach>
</select>
AI 代码解读
具体的测试代码如下
@Test
public void testSelectForTwo(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> stuList = new ArrayList<>();
Student s1 = new Student();
s1.setId(1002);
s1.setName("lisi");
stuList.add(s1);
s1 = new Student();
s1.setId(1005);;
s1.setName("zs");
stuList.add(s1);
List<Student> students = dao.selectForeachTwo(stuList);
for(Student stu:students){
System.out.println("foreach--two ==="+stu);
}
}
AI 代码解读
6.4 动态sql
1.先定义 <sql id="自定义名称唯一"> sql语句, 表名,字段等 </sql>
2.再使用, <include refid="id的值" />
<!--定义sql片段-->
<sql id="studentSql">
select id,name, age, email from student
</sql>
AI 代码解读
之后在下边这样定义
<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
<include refid="studentSql" />
where id > 0
<if test="name !=null and name !='' ">
and name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</select>
AI 代码解读
7. 配置文件
- 定义别名
- 数据源
- mapper 文件
其中定义别名上面已经讲过了这里就回顾一下
<!--定义别名-->
<typeAliases>
<!--
第一种方式:
可以指定一个类型一个自定义别名
type:自定义类型的全限定名称
alias:别名(短小,容易记忆的)
-->
<!--<typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
<typeAlias type="com.bjpowernode.vo.ViewStudent" alias="vstu" />-->
<!--
第二种方式
<package> name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)
-->
<package name="com.bjpowernode.domain"/>
<package name="com.bjpowernode.vo"/>
</typeAliases>
AI 代码解读
7.1 数据库配置
数据库的属性配置文件: 把数据库连接信息放到一个单独的文件中。 和mybatis主配置文件分开。
目的是便于修改,保存,处理多个数据库的信息。
在resources目录中定义一个属性配置文件, xxxx.properties ,例如 jdbc.properties
在属性配置文件中, 定义数据,格式是 key=value
key: 一般使用 . 做多级目录的。
例如 jdbc.mysql.driver , jdbc.driver, mydriver
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql//.....
jdbc.username=root
jdbc.password=123456
在mybatis的主配置文件,使用<property>
指定文件的位置
在需要使用值的地方, ${key}
jdbc的配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springdb
jdbc.user=root
jdbc.passwd=123456
AI 代码解读
xml文件配置
<!--指定properties文件的位置,从类路径根开始找文件-->
<properties resource="jdbc.properties" />
AI 代码解读
具体的下面的配置文件这么定义
具体链接数据库文件的注释如下
<environments default="mydev">
<environment id="mydev">
<!--
transactionManager:mybatis提交事务,回顾事务的方式
type: 事务的处理的类型
1)JDBC : 表示mybatis底层是调用JDBC中的Connection对象的,commit, rollback
2)MANAGED : 把mybatis的事务处理委托给其它的容器(一个服务器软件,一个框架(spring))
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示数据源,java体系中,规定实现了javax.sql.DataSource接口的都是数据源。
数据源表示Connection对象的。
type:指定数据源的类型
1)POOLED: 使用连接池, mybatis会创建PooledDataSource类
2)UPOOLED: 不使用连接池, 在每次执行sql语句,先创建连接,执行sql,在关闭连接
mybatis会创建一个UnPooledDataSource,管理Connection对象的使用
3)JNDI:java命名和目录服务(windows注册表)
-->
<dataSource type="POOLED">
<!--数据库的驱动类名-->
<property name="driver" value="${jdbc.driver}"/>
<!--连接数据库的url字符串-->
<property name="url" value="${jdbc.url}"/>
<!--访问数据库的用户名-->
<property name="username" value="${jdbc.user}"/>
<!--密码-->
<property name="password" value="${jdbc.passwd}"/>
</dataSource>
</environment>
</environments>
AI 代码解读
7.2 mapper位置
mapper(sql映射文件)的位置
- 第一种方式:指定多个mapper文件
<!-- sql mapper(sql映射文件)的位置-->
<mappers>
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
<mapper resource="com/bjpowernode/dao/OrderDao.xml" />
</mappers>
AI 代码解读
- 第二种方式: 使用包名
name: xml文件(mapper文件)所在的包名, 这个包中所有xml文件一次都能加载给mybatis使用package的要求:
- mapper文件名称需要和接口名称一样, 区分大小写的一样
- mapper文件和dao接口需要在同一目录
<!-- sql mapper(sql映射文件)的位置-->
<mappers>
<package name="com.bjpowernode.dao"/>
<!-- <package name="com.bjpowernode.dao2"/>
<package name="com.bjpowernode.dao3"/>-->
</mappers>
AI 代码解读
8. PageHelper
分页的功能
添加依赖包
<!--PageHelper依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
AI 代码解读
在mybatis.xml下添加插件
这个插件的功能类似数据库关键字中的limit
<!--配置插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
AI 代码解读
通过一个方法测试使用
//使用PageHelper分页数据
List<Student> selectAll();
AI 代码解读
<!--查询所有-->
<select id="selectAll" resultType="com.bjpowernode.domain.Student">
select * from student order by id
</select>
AI 代码解读
具体的测试代码如下
@Test
public void testSelectAllPageHelper(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//加入PageHelper的方法,分页
// pageNum: 第几页, 从1开始
// pageSize: 一页中有多少行数据
PageHelper.startPage(1,3);
List<Student> students = dao.selectAll();
for(Student stu:students){
System.out.println("foreach--one ==="+stu);
}
}
AI 代码解读