一、MyBatis简介
1.1 什么是Mybatis
- MyBatis 是一款优秀的持久层框架
- 它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
如何获得Mybatis?
- maven仓库
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency>
- Github:github.com/mybatis/myb…
- 中文文档:mybatis.org/mybatis-3/z…
1.2 持久化
数据持久化
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据库(JDBC),I/O文件持久化
- 生活:冷藏、罐头
1.3 持久层
Dao层、Service层、Controller层
- 完成持久化工作的代码块
- 层的界限十分明显
1.4 为什么需要Mybatis?
- 帮助程序员将数据存储到数据库中
- 方便、传统的JDBC代码太复杂,Mybatis框架更容易上手
- 简单易学、灵活
- sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库
- orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql。
- 最重要的一点:使用的人多
二、第一个Mybatis程序
思路:
1.创建父工程 引入mysql mybatis Junit 依赖
2.maven子工程 编写mybatis核心配置文件 mybatis-config.xml 连接数据库
3.untils层 pojo层 dao层
4.编写mybatis工具类 编写实体类
5.编写Mapper接口 以及对应UseMapper.xml配置文件
6.Junit测试
2.1 新建项目
建立mysql数据库
CREATE DATABASE MYBATIS; USE MYBATIS; CREATE TABLE user( id INT(20) NOT NULL PRIMARY KEY, name VARCHAR(30) DEFAULT NULL, pwd VARCHAR(30) DEFAULT NULL )ENGINE = INNODB DEFAULT CHARSET = utf8; INSERT INTO user(id, name, pwd) VALUES (1, '孙孙孙', 2002), (2, '铭铭铭', 1208), (3, '孙不坚', 1234);
新建项目 1.新建一个普通的maven项目 2.删除src目录 3.导入maven依赖
将该工程当做父工程
<!--导入依赖--> <dependencies> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--mybatis驱动--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <!--junit驱动--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
4.创建子工程
2.2 创建一个模块
- 编写Mybatis的核心配置文件
<?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核心配置文件--> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="sm1208"/> </dataSource> </environment> </environments> <!--每一个Mapper.xml都需要Mybatis核心配置文件中注册!--> <mappers> <mapper resource="com/sun/dao/UserMapper.xml"/> </mappers> </configuration>
- 编写Mybatis的工具类
package com.sun.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; //sqlSessionFactory --> sqlSession public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory = null; static { try { // 使用Mybatis 第一步:获取sqlSessionFactory对象 String resource = "mybatis-config.xml"; InputStream in = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); } catch (IOException e) { e.printStackTrace(); } } // 有了SqlSessionFactory,顾名思义,我们就可以从中获得 SqlSession 的实例了 // SqlSession 完全包含了面向数据库执行 SQL 命令所需要的所有方法 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
2.3 编写代码
- 实体类
package com.sun.pojo; public class User { private int id; private String name; private String pwd; public User() { } public User(int id, String name, String pwd) { this.id = id; this.name = name; this.pwd = pwd; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } }
- Mapper接口
package com.sun.dao; import com.sun.pojo.User; import java.util.List; public interface UserMapper { //查询所有的用户 List<User> getUserList(); }
- 接口实现类,由原来的UserDaoImp转变为一个Mapper配置文件,即UseMapper.xml
<?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接口 --> <mapper namespace="com.sun.dao.UserMapper"> <!-- select查询语句 --> <select id="getUserList" resultType="com.sun.pojo.User"> select * from mybatis.user; </select> </mapper>
2.4 测试
- junit 测试
package com.sun.dao; import com.sun.pojo.User; import com.sun.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; public class UserMapperTest { @Test public void test(){ // 第一步:获取SqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); // 方式一:getMapper UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.getUserList(); for (User user : userList) { System.out.println(user); } // 关闭 SqlSession sqlSession.close(); } }
2.5 常见问题
a 解决maven引入依赖资源过滤问题
<!-- 在build中配置resources,防止资源导出失败的问题 --> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
b 解决xml文件中文字符集产生报错的问题
//引入依赖 <!-- <properties>--> <!-- <!– 设置默认编码 –>--> <!-- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>--> <!-- </properties>-->
c 核心配置文件中注册 mappers
注意点:org.apache.ibatis.binding.BindingException: Type interface com.xulong.dao.UserDao is not known to the MapperRegistry.
<!--每一个Mapper.xml都需要Mybatis核心配置文件中注册!--> <mappers> <mapper resource="com/sun/dao/UserMapper.xml"/> </mappers>
三、CRUD
- namespace中的包名要和 Dao/Mapper 接口的包名一致
- 在xml文件sql
- id : 就是对应的 namespace 中的方法名
- resultType : Sql 语句执行的返回值
- parameterType :参数类型
- 编写接口 编写对应Mapper中的sql语句 编写测试
- 增 删 改 需要提交事务 !
1. Select
//根据ID查询用户 User getUserByID(int id)
<select id="getUserByID" parameterType="int" resultType="com.sun.pojo.User"> select * from mybatis.user where id = #{id}; </select>
@Test public void getUserByID(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserByID(1); System.out.println(user); sqlSession.close(); }
2. Insert
int addUser(User user);
<!-- 对象中的属性可以直接取出来 --> <insert id="addUser" parameterType="com.sun.pojo.User"> insert into mybatis.user (id, name, pwd) values (#{id}, #{name}, #{pwd}); </insert>
@Test public void addUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(4, "孙明明", "1324214"); int result = mapper.addUser(user); if (result > 0){ System.out.println("插入成功!"); } //提交事务 sqlSession.commit(); sqlSession.close(); }
3. Updata
//修改用户 int updateUser(User user);
<update id="updateUser" parameterType="com.sun.pojo.User"> update mybatis.user set name = #{name}, pwd = #{pwd} where id = #{id}; </update>
@Test public void updateUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(5, "旺财", "14432434"); mapper.updateUser(user); int result = mapper.updateUser(user); if (result > 0){ System.out.println("修改成功!"); } sqlSession.commit(); sqlSession.close(); }
4. Delete
//删除用户 int deleteUser(int id);
<delete id="deleteUser" parameterType="int"> delete from mybatis.user where id = #{id}; </delete>
@Test public void deleteUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.deleteUser(4); sqlSession.commit(); sqlSession.close(); }
5. Map
假设我们的实体类,数据库中的表、字段或者参数过多,我们应当考虑使用Map。
//万能的Map int addUser1(Map<String, Object> map);
<!-- 对象中的属性可以直接取出来 传递Map中的key --> <insert id="addUser1" parameterType="Map"> insert into mybatis.user (id, name, pwd) values (#{userid}, #{username}, #{password}); </insert>
@Test public void addUser1(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String, Object> map = new HashMap<>(); map.put("userid", 5); map.put("username", "赵六"); map.put("password", "144324324"); mapper.addUser1(map); sqlSession.close(); }
Map传递参数,直接在sql中取出key即可【parameterType=“Map”】 对象传递参数,直接在sql中取对象的属性即可【parameterType=“Object”】 只有一个基本类型参数的情况下,可以直接在sql中取到,不需要parameterType的设置 多个参数用Map,或者注解
四、核心配置解析
mybatis-config.xml配置解析
1. 属性 (properties)
xml里属性都是可外部配置且可动态替换的,我们可以通过properties属性来实现引用配置文件。
- 编写一个配置文件 db.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username=root password=sm1208
- 在核心配置文件中引入
- 直接引入外部文件
<!-- 引入外部配置文件 --> <properties resource="db.properties"> </properties>
- 可以在其中增加一些属性配置
<!-- 引入外部配置文件 --> <properties resource="db.properties"> <property name="username" value="root"/> <property name="password" value="sm1208"/> </properties>
- 如果两个文件有同一个字段,优先使用外部配置文件
2. 设置 (settings)
3. 类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
- 第一种配置方式 ,User 可以用在任何使用 com.sun.pojo.User 的地方使用。
<typeAliases> <typeAlias alias="User" type="com.sun.pojo.User"/> </typeAliases>
- 第二种配置方式,指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,例如: 扫描实体类pojo的包,它的默认别名就为这个类的类名User。
<typeAliases> <package name="com.sun.pojo"/> </typeAliases>
在实体类比较少的情况,推荐使用第一种方式,如果实体类多的情况下,建议使用第二种方式,第一种可以DIY别名,第二种则不行,如果想实现第二种的DIY,在第二种配置方式的基础上还需要在实体类上增加注解:
import org.apache.ibatis.type.Alias; @Alias("hello") public class User { }
4. 类型处理器(typeHandlers)
5. 对象工厂(objectFactory)
6. 插件(plugins)
7. 环境配置(environments)
MyBatis 可以配置成适应多种环境,尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
- 默认使用的环境 ID(比如:default="development")。
- 每个 environment 元素定义的环境 ID(比如:id="development")。
- 事务管理器的配置(比如:type="JDBC")。
- 数据源的配置(比如:type="POOLED")。
环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID。
8. 数据库厂商标识(databaseIdProvider)
9. 映射器(mappers)
MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件,**即映射器注册问题MapperRegistry:注册绑定我们的Mapper文件。**你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:///
形式的 URL),或类名和包名等。例如:
- 【推荐使用】
<!-- 使用相对于类路径的资源引用 --> <mappers> <mapper resource="com/sun/dao/UserMapper.xml"/> </mappers>
- 使用class文件进行绑定
<!-- 使用映射器接口实现类的完全限定类名 --> <mappers> <mapper class="com.sun.dao.UserMapper"/> </mappers>
- 接口和其对应的Mapper配置文件必须同名
- 接口和其对应的Mapper配置文件必须在同一个包下
- 使用扫描包进行注入绑定
<!-- 将包内的映射器接口实现全部注册为映射器 --> <mappers> <package name="com.sun.dao"/> </mappers>
- 接口和其对应的Mapper配置文件必须同名
- 接口和其对应的Mapper配置文件必须在同一个包下
10. 生命周期和作用域
五、使用注解开发
1. 面向接口编程
大家之前都学习过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程。 根本原因:解耦,可拓展,提高复用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好。 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协助完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了。 而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大道各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是按照这种思想来编程。
关于接口的理解
- 接口从更深层次的理解,应是定义(规范、约束)与实现(名实分离的原则)的分离。
- 接口的本身反映了系统设计人员对系统的抽象理解。
- 接口应有两种
- 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class)
- 第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface)
- 一个体可能有多个抽象面,抽象体和抽象面是有区别的。
三个面向区别
- 面向向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法。
- 面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现。
- 接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题,更多的体现就是对系统整体的架构。
2. 使用注解开发
- 注解在接口上实现
@Select("select * from user") List<User> get
- 在核心配置文件中绑定接口
<!-- 绑定接口 --> <mappers> <mapper class="com.fj.dao.UserMapper"/> </mappers>
- 测试
@Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); //底层主要应用反射 UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.getUsers(); for (User user : users){ System.out.println(user); } sqlSession.close(); }
本质:反射机制实现底层:动态代理
Mybatis详细执行流程
3.注解-CRUD
- 我们可以在工具类创建的时候实现自动提交事务
public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(true); }
- 编写接口,添加注解
@Select("select * from user") List<User> getUsers(); // 方法中如果有多个参数,那么每一个参数前都必须加上@Param("") @Select("select * from user where id = #{id}") User getUserByID(@Param("id") int id); // User getUserByID(@Param("id") int id, @Param("name") String name); @Insert("insert into user (id, name, pwd) values (#{id}, #{name}, #{password})") int addUser(User user); @Update("update user set name = #{name}, pwd = #{password} where id = #{id}") int updateUser(User user); @Delete("delete from user where id = #{id}") int deleteUser(@Param("id") int id);
- 测试类
- 【注意,我们必须要将接口绑定到核心配置文件mybatis-config.xml文件中】
<!-- 绑定接口 --> <mappers> <mapper class="com.sun.dao.UserMapper"/> </mappers>