MyBatis学习笔记(动力节点学习的)
2021/7/17 6:05:17
本文主要是介绍MyBatis学习笔记(动力节点学习的),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
MyBatis框架
在 http://www.bjpowernode.com学习的这个框架
什么是框架
框架定义
框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种认为,框架是可被应用开发者定制的应用骨架、模板。
简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。从另一个角度来说框架一个舞台,你在舞台上做表演。在框架基础上加入你要完成的功能。
框架安全的,可复用的,不断升级的软件。
框架解决的问题
框架要解决的最重要的一个问题是技术整合,在 J2EE 的 框架中,有着各种各样的技术,不同的应用,系统使用不同的技术解决问题。需要从 J2EE 中选择不同的技术,而技术自身的复杂性,有导致更大的风险。企业在开发软件项目时,主要目的是解决业务问题。 即要求企业负责技术本身,又要求解决业务问题。这是大多数企业不能完成的。框架把相关的技术融合在一起,企业开发可以集中在业务领域方面。
另一个方面可以提供开发的效率。
常用框架介绍
MyBatis框架
MyBatis 是一个优秀的基于 java 的持久层框架,内部封装了 jdbc,开发者只需要关注 sql 语句本身,而不需要处理加载驱动、创建连接、创建 statement、关闭连接,资源等繁杂的过程。MyBatis 通过 xml 或注解两种方式将要执行的各种 sql 语句配置起来,并通过java 对象和 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。
MyBatis 本是 apache 的一个开源项目 iBatis, 2010 年这个项目由 apache software foundation 迁移到了 google code,并且改名为 MyBatis 。2013 年 11 月迁移到 Github。iBATIS 一词来源于“internet”和“abatis”的组合,是一个基于 Java 的持久层框架。iBATIS 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAOs)
当前,最新版本是 MyBatis 3.5.2 ,其发布时间是 2019年9月21日
Spring框架
Spring 框架为了解决软件开发的复杂性而创建的。Spring 使用的是基本的 JavaBean 来完成以前非常复杂的企业级开发。Spring 解决了业务对象,功能模块之间的耦合,不仅在 javase,web 中使用,大部分 Java 应用都可以从 Spring 中受益。
Spring 是一个轻量级控制反转(IOC)和面向切面(AOP)的容器。
SpringMVC框架
Spring MVC 属于 SpringFrameWork 3.0 版本加入的一个模块,为 Spring 框架提供了构建 Web 应用程序的能力。现在可以 Spring 框架提供的 SpringMVC 模块实现 web 应用开发,在 web 项目中可以无缝使用 Spring 和 Spring MVC 框架。
JDBC 编程
使用 JDBC 编程的回顾
public void findStudent() { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { //注册 mysql 驱动 Class.forName("com.mysql.jdbc.Driver"); //连接数据的基本信息 url ,username,password String url = "jdbc:mysql://localhost:3306/springdb"; String username = "root"; String password = "123456"; //创建连接对象 conn = DriverManager.getConnection(url, username, password); //保存查询结果 List<Student> stuList = new ArrayList<>(); //创建 Statement, 用来执行 sql 语句 stmt = conn.createStatement(); //执行查询,创建记录集, rs = stmt.executeQuery("select * from student"); while (rs.next()) { Student stu = new Student(); stu.setId(rs.getInt("id")); stu.setName(rs.getString("name")); stu.setAge(rs.getInt("age")); //从数据库取出数据转为 Student 对象,封装到 List 集合 stuList.add(stu); } } catch (Exception e) { e.printStackTrace(); } finally { try { //关闭资源 if (rs != null){ rs.close() } if (stmt != null) { stmt.close(); } if (conn != null) { conn.close(); } } catch (Exception e) { e.printStackTrace(); } }
使用 JDBC 的缺陷
-
代码比较多,开发效率低
-
需要关注 Connection ,Statement, ResultSet 对象创建和销毁
-
对 ResultSet 查询的结果,需要自己封装为 List
-
重复的代码比较多些
-
业务代码和数据库的操作混在一起
MyBatis解决的主要问题
减轻使用 JDBC 的复杂性,不用编写重复的创建 Connetion , Statement ; 不用编写关闭资源代码。直接使用 java 对象,表示结果数据。让开发者专注 SQL 的处理。 其他分心的工作由 MyBatis 代劳。
MyBatis 可以完成:
-
注册数据库的驱动,例如 Class.forName(“com.mysql.jdbc.Driver”))
-
创建 JDBC 中必须使用的 Connection , Statement, ResultSet 对象
-
从 xml 中获取 sql,并执行 sql 语句,把 ResultSet 结果转换 java 对象
List<Student> list = new ArrayLsit<>(); ResultSet rs = state.executeQuery(“select * from student”); while(rs.next){ Student student = new Student(); student.setName(rs.getString(“name”)); student.setAge(rs.getInt(“age”)); list.add(student); }
4.关闭资源
ResultSet.close() , Statement.close() , Conenection.close()
使用 Mybatis 准备(快速入门)
1.下载 mybatis
https://github.com/mybatis/mybatis-3/releases
2.搭建 MyBatis 开发环境
数据库名 ssm ;表名 student
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1001,"孙尚香","sunshangxiang@qq.com",23); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1002,"凌统","lingtong@qq.com",42); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1003,"吕布","lvbu@qq.com",34); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1004,"张苞","zhangbao@qq.com",55); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1005,"赵云","zhaoyun@qq.com",43); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1006,"关羽","guanyu@qq.com",45); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1007,"马超","machao@qq.com",62); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1008,"黄忠","huangzhong@qq.com",22); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1009,"张飞","zhangfei@qq.com",65); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1010,"夏侯渊","xiahouyuan@qq.com",89); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1011,"邓艾","dengai@qq.com",34); INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1012,"霍去病","huoqubing@qq.com",18);
3.创建 maven 工程
模板:
工程坐标:
4.加入maven坐标
pom.xml 加入 maven 坐标:
<dependencies> <!--Junit依赖--> <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>
说明:MyBatis的GAV坐标,可以在下载的MyBatis文件目录的说明文档中查看
5.加入 maven 插件
pom.xml 加入maven插件:
<build> <resources> <resource> <directory>src/main/java</directory><!--所在的目录--> <includes><!--包括目录下的.properties.xml 文件都会扫描到--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
6.编写 Student 实体类
创建 com.atguigu.pojo包,创建实体类
package com.atguigu.pojo; /** * 对应ssm数据库的student表 */ public class Student { //属性名和列名一样 private Integer id; private String name; private String email; private Integer age; //get/set/toString/constructor //代码略。。。 }
7.编写 Dao 接口 StudentDao
创建com.atguigu.dao包,创建StudentDao接口
package com.atguigu.dao; import com.atguigu.pojo.Student; import java.util.List; /** * Dao接口 */ public interface StudentDao { /** * 查询所有学生信息 * @return 学生信息的List集合 */ public List<Student> selectStudents(); }
8.编写 Dao 接口 Mapper 映射文件 StudentDao.xml
要求:
-
在 dao 包中创建文件 StudentDao.xml
-
要 StudentDao.xml 文件名称和接口 StudentDao 一样,区分大小写的一样
<?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"> <!-- namespace:必须有值,自定义的唯一字符串 推荐使用:dao 接口的全限定名称 --> <mapper namespace="com.atguigu.dao.StudentDao"> <!-- <select>: 查询数据, 标签中必须是 select 语句 id: sql 语句的自定义名称,推荐使用 dao 接口中方法名称, 使用名称表示要执行的 sql 语句 resultType: 查询语句的返回结果数据类型,使用全限定类名 --> <select id="selectStudents" resultType="com.atguigu.pojo.Student"> <!--要执行的 sql 语句--> select id,name,email,age from student </select> </mapper>
9.创建 MyBatis 主配置文件
项目 src/main 下创建 resources 目录,设置 resources 目录为 resources root
创建主配置文件:名称为 mybatis.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> <!--配置 mybatis 环境--> <environments default="mysql"> <!--id:数据源的名称--> <environment id="mysql"> <!--配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚)--> <transactionManager type="JDBC"/> <!--数据源 dataSource:创建数据库 Connection 对象 type: POOLED 使用数据库的连接池 --> <dataSource type="POOLED"> <!--连接数据库的四个要素--> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/ssm"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <!--告诉 mybatis 要执行的 sql 语句的位置--> <mapper resource="com/atguigu/dao/StudentDao.xml"/> </mappers> </configuration>
支持中文的 url
jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8
10.创建测试类 MyBatisTest
@Test public void testStart() throws IOException { //访问mybatis读取student数据 //1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess) String config = "MyBatis.xml"; //2.读取配置文件 InputStream is = Resources.getResourceAsStream(config); //3.创建了SqlSessionFactoryBuilder对象,目的是获取SqlSession SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //4.获取SqlSession,SqlSession能执行sql语句 //SqlSession sqlSession = factory.openSession(true);//true表示设置为自动提交事务 SqlSession sqlSession = factory.openSession(); //5.【重要】指定要执行的sql语句的标识,sql映射文件中的namespace + "." + 标签的id值 List<Student> studentList = sqlSession.selectList("com.atguigu.dao.StudentDao.selectStudents"); //mybatis默认不是自动提交事务的,所以在insert,update,delete后要手动提交事务(select语句不用) //sqlSession.commit(); //6.循环输出查询结果 for(Student student : studentList){ System.out.println(student); } //7.关闭SqlSession,释放资源 sqlSession.close(); }
说明:
//5.【重要】指定要执行的sql语句的标识,sql映射文件中的namespace + "." + 标签的id值 List<Student> studentList = sqlSession.selectList("com.atguigu.dao.StudentDao.selectStudents");
近似等价于jdbc中代码
Connection conn = 获取连接对象 String sql=” select id,name,email,age from student” PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery();
11.配置日志功能
mybatis.xml 文件加入日志配置,可以在控制台输出执行的 sql 语句和参数
<settings> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings>
配置日志文件,查询后控制台输出的信息:
G:\developer_tools\java1.8\jdk1.8\bin\java ... Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. Opening JDBC Connection Created connection 1136497418. Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@43bd930a] ==> Preparing: select id,name,email,age from student ==> Parameters: <== Columns: id, name, email, age <== Row: 1001, 孙尚香, sunshangxiang@qq.com, 23 <== Row: 1002, 凌统, lingtong@qq.com, 42 <== Row: 1003, 吕布, lvbu@qq.com, 34 <== Row: 1004, 张苞, zhangbao@qq.com, 55 <== Row: 1005, 赵云, zhaoyun@qq.com, 43 <== Row: 1006, 关羽, guanyu@qq.com, 45 <== Row: 1007, 马超, machao@qq.com, 62 <== Row: 1008, 黄忠, huangzhong@qq.com, 22 <== Row: 1009, 张飞, zhangfei@qq.com, 65 <== Row: 1010, 夏侯渊, xiahouyuan@qq.com, 89 <== Row: 1011, 邓艾, dengai@qq.com, 34 <== Row: 1012, 霍去病, huoqubing@qq.com, 18 <== Total: 12 Student{id=1001, name='孙尚香', email='sunshangxiang@qq.com', age=23} Student{id=1002, name='凌统', email='lingtong@qq.com', age=42} Student{id=1003, name='吕布', email='lvbu@qq.com', age=34} Student{id=1004, name='张苞', email='zhangbao@qq.com', age=55} Student{id=1005, name='赵云', email='zhaoyun@qq.com', age=43} Student{id=1006, name='关羽', email='guanyu@qq.com', age=45} Student{id=1007, name='马超', email='machao@qq.com', age=62} Student{id=1008, name='黄忠', email='huangzhong@qq.com', age=22} Student{id=1009, name='张飞', email='zhangfei@qq.com', age=65} Student{id=1010, name='夏侯渊', email='xiahouyuan@qq.com', age=89} Student{id=1011, name='邓艾', email='dengai@qq.com', age=34} Student{id=1012, name='霍去病', email='huoqubing@qq.com', age=18} Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@43bd930a] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@43bd930a] Returned connection 1136497418 to pool. Process finished with exit code 0
基本的CRUD
insert
(1)StudentDao 接口中增加方法
/** * 添加一条学生信息 * @param student * @return 影响的行数 */ public int insertStudent(Student student);
(2)StudentDao.xml 加入 sql 语句
<!-- #{数据} 中的数据要与类中的属性保持一致--> <insert id="insertStudent"> insert into student(id,name,email,age) values(#{id},#{name},#{email},#{age}) </insert>
(3)测试方法
@Test public void testInsertStudent() throws IOException { //固定获取SqlSession的步骤 String config = "MyBatis.xml"; InputStream is = Resources.getResourceAsStream(config); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = factory.openSession(); //创建保存数据的对象 Student student = new Student(1013, "袁崇焕", "yuanchonghuan@qq.com", 32); //执行插入insert int result = sqlSession.insert("com.atguigu.dao.StudentDao.insertStudent",student); //提交事务(默认是不提交) sqlSession.commit(); System.out.println("增加记录的行数:" + result); //关闭SqlSession sqlSession.close(); }
执行测试方法后控制台输出信息:
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. Opening JDBC Connection Created connection 110431793. Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6950e31] ==> Preparing: INSERT INTO student (id,name,email,age)VALUES(?,?,?,?) ==> Parameters: 1013(Integer), 袁崇焕(String), yuanchonghuan@qq.com(String), 32(Integer) <== Updates: 1 Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6950e31] 增加记录的行数:1 Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6950e31] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6950e31] Returned connection 110431793 to pool.
update
(1)StudentDao接口中增加方法
/** * 修改一条学生信息 * @param student * @return 影响的行数 */ public int updateStudent(Student student);
(2)StudentDao.xml加入sql语句
<!-- #{数据} 中的数据要与类中的属性保持一致--> <update id="updateStudent"> update student set age = #{age} where id = #{id} </update>
(3)测试方法
@Test public void testUpdateStudent() throws IOException { //固定获取SqlSession的步骤 String config = "MyBatis.xml"; InputStream is = Resources.getResourceAsStream(config); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = factory.openSession(); //创建保存数据的对象 Student student = new Student(); student.setId(1013); student.setAge(99); //执行更新 int result = sqlSession.update("com.atguigu.dao.StudentDao.updateStudent", student); //提交事务(默认是不提交) sqlSession.commit(); System.out.println("修改记录的行数:" + result); //关闭SqlSession sqlSession.close(); }
delete
(1)StudentDao 接口中增加方法
/** * 删除一条学生信息 * @param id 需要删除学生的id * @return 影响的行数 */ public int deleteStudent(int id);
**(2)StudentDao.xml 加入 sql 语句 **
<!-- #{数据} 中的数据要与类中的属性保持一致--> <delete id="deleteStudent" parameterType="java.lang.Integer"> delete from student where id = #{id} </delete>
(3)测试方法
@Test public void testDeleteStudent() throws IOException { //获取SqlSession的固定步骤 String config = "MyBatis.xml"; InputStream is = Resources.getResourceAsStream(config); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = factory.openSession(); //执行删除方法 int result = sqlSession.delete("com.atguigu.dao.StudentDao.deleteStudent",1003); //提交事务(默认是不提交) sqlSession.commit(); System.out.println("删除记录的行数:" + result); //关闭SqlSession sqlSession.close(); }
MyBatis中使用的对象介绍
Resources 类
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象。
//1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess) String config = "MyBatis.xml"; //2.读取这个配置文件 InputStream is = Resources.getResourceAsStream(config);
SqlSessionFactoryBuilder 类
SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 由 于SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。
//3.创建了SqlSessionFactoryBuilder对象,目的是获取SqlSession SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSessionFactory 接口
SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。
-
openSession(true):创建一个有自动提交功能的 SqlSession
-
openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
-
openSession():同 openSession(false)
//4.获取SqlSession,SqlSession能执行sql语句 //SqlSession sqlSession = factory.openSession(true);//true表示设置为自动提交事务 SqlSession sqlSession = factory.openSession();
SqlSession 接口
SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。
SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将其关闭。再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭。
//5.【重要】指定要执行的sql语句的标识,sql映射文件中的namespace + "." + 标签的id值 List<Student> studentList = sqlSession.selectList("com.atguigu.dao.StudentDao.selectStudents"); //mybatis默认不是自动提交事务的,所以在insert,update,delete后要手动提交事务(select语句不用) //sqlSession.commit(); //6.循环输出查询结果 for(Student student : studentList){ System.out.println(student); } //7.关闭SqlSession,释放资源 sqlSession.close();
MyBatis使用CRUD操作优化
创建工具类MyBatisUtil获取SqlSession对象
package com.atguigu.utils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; /** * 获取SqlSession的工具类 */ public class MyBatisUtil { private static SqlSessionFactory factory = null; /** *因为SqlSessionFactory接口对象是一个重量级对象(系统开销大的对象) * 所以使用静态代码块创建一次SqlSessionFactory */ static{ try { //1.定义mybatis主配置文件的名称,从类路径的根开始(target/clasess) String config = "MyBatis.xml"; //2.读取配置文件 InputStream is = Resources.getResourceAsStream(config); //3.创建了SqlSessionFactoryBuilder对象,目的是获取SqlSession factory = new SqlSessionFactoryBuilder().build(is); } catch (IOException e) { factory = null; e.printStackTrace(); } } /** * 获取SqlSession对象 * @return SqlSession对象,获取失败则返回null */ public static SqlSession getSqlSession() { if (factory != null){ //4.获取SqlSession,SqlSession能执行sql语句 SqlSession sqlSession = factory.openSession(); return sqlSession; } return null; } }
测试方法:
@Test public void testMyBatisUtil(){ //使用MyBatisUtil工具类获取SqlSession对象 SqlSession sqlSession = MyBatisUtil.getSqlSession(); System.out.println(sqlSession); }
执行方法后,控制台输出:
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. org.apache.ibatis.session.defaults.DefaultSqlSession@627551fb
传统 Dao 开发方式的分析
(1)创建StudentDao的实现类StudentDaoImpl,实现接口中的方法
package com.atguigu.dao.impl; public class StudentDaoImpl implements StudentDao { @Override public List<Student> selectStudents() { SqlSession sqlSession = MyBatisUtil.getSqlSession(); List<Student> students = sqlSession.selectList("com.atguigu.dao.StudentDao.selectStudents"); sqlSession.close(); return students; } }
(2)测试方法:
private StudentDao studentDao = new StudentDaoImpl(); @Test public void selectStudents() { List<Student> students = studentDao.selectStudents(); for (Student student : students) { System.out.println(student); } }
在前面例子中自定义 Dao 接口实现类时发现一个问题:Dao 的实现类其实并没有干什么实质性的工作,它仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,真正对 DB 进行操作的工作其实是由框架通过 mapper 中的 SQL 完成的。
所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对DB 进行操作。这种对 Dao 的实现方式称为 Mapper 的动态代理方式。
Mapper 动态代理方式无需程序员实现 Dao 接口。接口是由 MyBatis 结合映射文件自动生成的动态代理实现的。
Dao动态代理实现CRUD
(1)去掉StudentDao接口的实现类StudentDaoImpl,
(2)通过SqlSession的getMapper()方法获取StudentDaoImpl(原理为反射动态代理)
(3)getMapper()方法的参数为指定Dao接口类的class值
测试方法:
@Test public void testProxyDao(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); //用代理Dao类查询全部学生 List<Student> students = dao.selectStudents(); for (Student student : students) { System.out.println(student); } //用代理Dao类 插入方法 Student student = new Student(1013, "袁崇焕", "yuanchonghuan@qq.com", 25); int insertStudent = dao.insertStudent(student); //手动提交事务 sqlSession.commit(); System.out.println("插入学生成功,影响行数:" + insertStudent); }
原理
动态代理
/** * 查看动态代理源码入口 */ @Test public void testProxy(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao studentDao = sqlSession.getMapper(StudentDao.class); System.out.println(studentDao); }
执行方法后输出:
org.apache.ibatis.binding.MapperProxy@1f36e637
查看依赖jar包,进入源码查看...
深入理解参数
ParameterType
parameterType: 接口中方法参数的类型, 类型的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以推断出具体传入语句的参数,默认值为未设置(unset)。接口中方法的参数从 java 代码传入到mapper 文件的 sql 语句。
-
int 或 java.lang.Integer
-
hashmap 或 java.util.HashMap
-
list 或 java.util.ArrayList
-
student 或 com.bjpowernode.domain.Student
更多看 mybatis-3.5.1.pdf 的 15 页。
<select>,<insert>,<update>,<delete>都可以使用parameterType指定类型
例如:
<delete id="deleteStudent" parameterType="int"> delete from student where id=#{studentId} </delete>
等同于
<delete id="deleteStudent" parameterType="java.lang.Integer"> delete from student where id=#{studentId} </delete>
MyBatis参数传递
从 java 代码中把参数传递到 mapper.xml 文件。
一个简单参数
Dao 接口中方法的参数只有一个简单类型(java 基本类型和 String),占位符 #{ 任意字符 },和方法的参数名无关。
接口方法
/** * 通过id 查询学生信息(一个简单参数) * @param id * @return */ public Student selectById(int id);
mapper 文件:
<select id="selectById" resultType="com.atguigu.pojo.Student"> select id,name,email,age from student where id = #{studentId} </select>
测试方法
/** * 通过id 查询学生信息(一个简单参数) */ @Test public void testSelectById(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); Student student = dao.selectById(1005); System.out.println(student); }
多个参数-使用@Param
当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”),
mapper 文件使用#{自定义参数名}。
接口方法
/** * 通过name 或 age 查询学生(多参数传递,使用@Param) * @param name * @param age * @return */ public List<Student> selectMultiParam(@Param("studentName") String name,@Param("studentAge") int age);
mapper文件
<select id="selectMultiParam" resultType="com.atguigu.pojo.Student"> select id,name,email,age from student where name = #{studentName} or age = #{studentAge} </select>
测试方法
/** * 通过name 或 age 查询学生(多参数传递,使用@Param) */ @Test public void testSelectMultiParam(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); List<Student> students = dao.selectMultiParam("吕布", 22); for (Student student : students) { System.out.println(student); } }
多个参数-使用对象
使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。
语法格式: #{ property,javaType=java中数据类型名,jdbcType=数据类型名称 }
javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property }
mybatis-3.5.1.pdf 第 43 页 4.1.5.4 小节:
创建保存参数值的对象 QueryParam
package com.atguigu.vo; /** * 保存参数值的对象 */ public class QueryParam { private String queryName; private int queryAge; //get,set ...
接口方法
/** * 通过name或age查询学生(多个参数-使用对象) * @param queryParam * @return 学生信息的List集合 */ public List<Student> selectMultiObject(QueryParam queryParam);
mapper文件
<select id="selectMultiObject" resultType="com.atguigu.pojo.Student"> select id,name,email,age from student where name=#{queryName} or age = #{queryAge} </select>
或
<!--不常用--> <select id="selectMultiObject" resultType="com.bjpowernode.domain.Student"> select id,name,email,age from student where name=#{queryName,javaType=string,jdbcType=VARCHAR} or age =#{queryAge,javaType=int,jdbcType=INTEGER} </select>
测试方法
/** * 通过name或age查询学生(多个参数-使用对象) */ @Test public void testSelectMultiObject(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); QueryParam queryParam = new QueryParam(); queryParam.setQueryName("孙尚香"); queryParam.setQueryAge(44); List<Student> students = dao.selectMultiObject(queryParam); for (Student student : students) { System.out.println(student); } }
多个参数-按位置
参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1}
注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式。
接口方法
/** * 通过name或age查询学生(多个参数-按位置) * @param name * @param age * @return 学生信息的List集合 */ public List<Student> selectByNameAndAge(String name,int age);
mapper文件
<select id="selectByNameAndAge" resultType="com.atguigu.pojo.Student"> select id,name,email,age from student where name=#{arg0} or age =#{arg1} </select>
测试方法
/** * 通过name或age查询学生(多个参数-按位置) */ @Test public void testSelectByNameAndAge(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); List<Student> students = dao.selectByNameAndAge("凌统", 22); for (Student student : students) { System.out.println(student); } }
多个参数-使用Map
Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key,
Object 类型的值存储参数。 mapper 文件使用# { key } 引用参数值。
接口方法
/** * 通过name或age查询学生(多个参数-使用Map) * @param map * @return */ public List<Student> selectMultiMap(Map<String,Object> map);
mapper文件
<select id="selectMultiMap" resultType="com.atguigu.pojo.Student"> select id,name,email,age from student where name = #{myName} or age = #{myAge} </select>
测试方法
/** * 通过name或age查询学生(多个参数-使用Map) */ @Test public void testSelectMultiMap(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); Map<String,Object> map = new HashMap<>(); map.put("myName","夏侯渊");// #{myName} map.put("myAge",22);// #{myAge} List<Student> students = dao.selectMultiMap(map); for (Student student : students) { System.out.println(student); } }
#和$的区别
# :占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句,
#{…}代替sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法。
$ :字符串替换,告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的
内容连接起来。主要用在替换表名,列名,不同列排序等操作。(有sql注入风险!)
封装 MyBatis 输出结果
resultType
resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。resultType 和 resultMap,不能同时使用。
1.简单类型
接口方法
/** * 查询学生个数(简单类型返回值) * @return */ public int countStudent();
mapper文件
<select id="countStudent" resultType="int"> select count(*) from student </select>
测试方法
/** * 查询学生个数(简单类型返回值) */ @Test public void testCountStudent(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); int countStudent = dao.countStudent(); System.out.println("学生总人数:" + countStudent); }
2.对象类型
接口方法
/** * 通过id查询学生信息(对象类型返回值) * @return */ public Student selectById();
mapper文件
<select id="selectById" resultType="com.atguigu.pojo.Student"> select id,name,email,age from student where id = #{studentId} </select>
测试方法
/** * 通过id 查询学生信息(一个简单参数) */ @Test public void testSelectById(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); Student student = dao.selectById(1005); System.out.println(student); }
框架的处理:使用构造方法创建对象。调用 setXXX 给属性赋值。
- Student student = new Student();
- 调用列名对应的set方法
sql 语句列 | java 对象方法 |
---|---|
id | setId( rs.getInt(“id”) ) |
name | setName( rs.getString(“name”) ) |
setEmail( rs.getString(“email”) ) | |
age | setAge( rs.getInt(“age”) ) |
注意:Dao 接口方法返回是集合类型,需要指定集合中的类型,不是集合本身。
3.Map类型
sql 的查询结果作为 Map 的 key 和 value。推荐使用 Map<Object,Object>。
注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录是错误。
接口方法
/** * 通过id查询学生信息(返回值为Map类型) * @param id * @return */ public Map<Object,Object> selectReturnMap(int id);
mapper文件
<select id="selectReturnMap" resultType="java.util.HashMap"> select id,name,email,age from student where id = #{studentId} </select>
测试方法
/** * 通过id查询学生信息(返回值为Map类型) */ @Test public void testSelectReturnMap(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); Map<Object, Object> returnMap = dao.selectReturnMap(1001); System.out.println("查询结果为:" + returnMap); }
resultMap
resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。
常用在列名和 java 对象属性名不一样的情况。
使用方式:
1.先定义 resultMap,指定列名和属性的对应关系。
2.在
mybatis.xml 主配置文件定义别名:
第一种方式(定义单个类型的别名)
<!--定义别名--> <typeAliases> <!-- 第一种方式: 定义单个类型的别名 type:自定义类型的全限定名称 alias:别名(短小,容易记忆的) --> <typeAlias type="com.atguigu.pojo.Student" alias="stu" /> <typeAlias type="com.atguigu.vo.ViewStudent" alias="vstu" />--> </typeAliases>
第二种方式(批量定义别名)
<!--定义别名--> <typeAliases> <!-- 第二种方式 批量定义别名,扫描整个包下的类,别名为类名(类名不区分大小写) <package> name:包名 --> <package name="com.atguigu.pojo"/> <package name="com.atguigu.vo"/> </typeAliases>
mappers(映射器)
(1)<mapper resource=" "/>(指定多个mapper文件)
使用相对于类路径的资源,从 classpath 路径查找文件
例如:
<mapper resource="com/atguigu/dao/StudentDao.xml" /> <mapper resource="com/atguigu/dao/OrderDao.xml" />
(2)<package name=" "/>
指定包下的所有 Dao 接口
例如:
<package name="com.atguigu.dao"/> <package name="com.atguigu.dao1"/> <package name="com.atguigu.dao2"/>
注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中
→修改后的主配置文件
<?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" /> <!--settings:控制mybatis全局行为--> <settings> <!--设置mybatis输出日志--> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <!--定义别名--> <typeAliases> <!-- 第一种方式: 可以指定一个类型一个自定义别名 type:自定义类型的全限定名称 alias:别名(短小,容易记忆的) --> <!-- <typeAlias type="com.atguigu.pojo.Student" alias="stu" /> <typeAlias type="com.atguigu.vo.ViewStudent" alias="vstu" />--> <!-- 第二种方式 <package> name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写) --> <package name="com.atguigu.pojo"/> <package name="com.atguigu.vo"/> </typeAliases> <!--配置 mybatis 环境--> <environments default="mysql"> <!--id:数据源的名称--> <environment id="mysql"> <!--配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚)--> <transactionManager type="JDBC"/> <!--数据源 dataSource:创建数据库 Connection 对象 type: POOLED 使用数据库的连接池 --> <dataSource type="POOLED"> <!--连接数据库的四个要素--> <!--使用 properties 文件: 语法 ${key}--> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!-- sql mapper(sql映射文件)的位置(告诉 mybatis 要执行的 sql 语句的位置)--> <mappers> <!--第一种方式:指定多个mapper文件--> <!-- <mapper resource="com/atguigu/dao/StudentDao.xml"/> <mapper resource="com/atguigu/dao/OrderDao.xml" /> --> <!-- 第二种方式: 使用包名 name: xml文件(mapper文件)所在的包名, 这个包中所有xml文件一次都能加载给mybatis 使用package的要求: 1. mapper文件名称需要和接口名称一样, 区分大小写 2. mapper文件和dao接口需要在同一目录 --> <package name="com.atguigu.dao" /> <!-- <package name="com.atguigu.dao2" /> <package name="com.atguigu.dao3" /> --> </mappers> </configuration>
PageHelper
Mybatis 通用分页插件
https://github.com/pagehelper/Mybatis-PageHelper
PageHelper 支持多种数据库:
-
Oracle
-
Mysql
-
MariaDB
-
SQLite
-
Hsqldb
-
PostgreSQL
-
DB2
-
SqlServer(2005,2008)
-
Informix
-
H2
-
SqlServer2012
-
Derby
-
Phoenix
基于 PageHelper 分页
实现步骤:
(1)maven坐标
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.10</version> </dependency>
(2)在mapper文件中加入plugin配置
在
<!--配置PageHelper插件--> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor" /> </plugins>
(3)PageHelper对象
查询语句之前调用 PageHelper.startPage 静态方法。除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。
在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个
方法后的第一个 MyBatis 查询方法会被进行分页。
@Test public void testSelect() throws IOException { //获取第 1 页,3 条内容 PageHelper.startPage(1,3); List<Student> studentList = studentDao.selectStudents(); studentList.forEach( stu -> System.out.println(stu)); }
这篇关于MyBatis学习笔记(动力节点学习的)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-27本地多文件上传的简单教程
- 2024-11-27低代码开发:初学者的简单教程
- 2024-11-27如何轻松掌握拖动排序功能
- 2024-11-27JWT入门教程:从零开始理解与实现
- 2024-11-27安能物流 All in TiDB 背后的故事与成果
- 2024-11-27低代码开发入门教程:轻松上手指南
- 2024-11-27如何轻松入门低代码应用开发
- 2024-11-27ESLint开发入门教程:从零开始使用ESLint
- 2024-11-27Npm 发布和配置入门指南
- 2024-11-27低代码应用课程:新手入门指南