MyBatis(一)Mybatis入门

ゞ 浴缸里的玫瑰 2021-06-22 15:37 713阅读 0赞

目录

  • 一、概述
  • 二、JDBC编程的分析
    • jdbc问题分析:
  • 三、mybatis环境搭建
      1. 前期准备
      • ① 创建一个maven工程
      • ② 创建一个数据库,供我们实验使用:
      1. 搭建mybatis开发环境
      • ① 导入依赖
      • ② 创建User类:
      • ③ 编写持久层接口`IUserDao`:
      • ④ 编写sqlMapConfig.xml配置文件:
      • ⑤ 编写持久层接口的映射文件 `IUserDao.xml:`
      • 总结
      1. 测试我们的demo
      • ①log4j的配置文件
      • ② 测试入口:
      • ③ 运行结果
      • 总结
  • 四、使用注解
  • 五、写Dao实现类
  • 六、分析
      1. mybatis入门案例中设计模式的分析
      1. 自定义mybatis的分析
      1. 创建代理对象的分析

一、概述

mybatis是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql语句本身, 而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。

mybatis通过xml 或注解的方式将要执行的各种statement配置起来,并通过java对象和statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并 返回。

采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc进行了封装,屏蔽了 jdbc api 底层访问细节,使我 们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。

了我们能够更好掌握框架运行的内部过程,并且有更好的体验,下面我们将从自定义 Mybatis 框架开始来 学习框架。此时我们将会体验框架从无到有的过程体验,也能够很好的综合前面阶段所学的基础。


二、JDBC编程的分析

我们回顾一下以前的JDBC编程方式:

  1. public static void main(String[] args) {
  2. Connection connection = null;
  3. PreparedStatement preparedStatement = null;
  4. ResultSet resultSet = null;
  5. try {
  6. // 加载数据库驱动
  7. Class.forName("com.mysql.jdbc.Driver");
  8. // 通过驱动管理类获取数据库链接
  9. connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8",
  10. "root", "0000");
  11. // 定义 sql 语句 ?表示占位符
  12. String sql = "select * from user where username = ?";
  13. // 获取预处理 statement
  14. preparedStatement = connection.prepareStatement(sql);
  15. // 设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的 参数值
  16. preparedStatement.setString(1, "王五");
  17. // 向数据库发出 sql 执行查询,查询出结果集
  18. resultSet = preparedStatement.executeQuery();
  19. // 遍历查询结果集
  20. while (resultSet.next()) {
  21. System.out.println(resultSet.getString("id") + "," + resultSet.getString("username"));
  22. }
  23. } catch (Exception e) {
  24. e.printStackTrace();
  25. } finally {
  26. // 释放资源
  27. if (resultSet != null) {
  28. try {
  29. resultSet.close();
  30. } catch (SQLException e) {
  31. e.printStackTrace();
  32. }
  33. if (preparedStatement != null) {
  34. try {
  35. preparedStatement.close();
  36. } catch (SQLException e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. if (connection != null) {
  41. try {
  42. connection.close();
  43. } catch (SQLException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. }
  48. }
  49. }

上边使用 jdbc 的原始方法(未经封装)实现了查询数据库表记录的操作。

jdbc问题分析:

  1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
  2. Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。
  3. 使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能 多也可能少,修改 sql 还要修改代码,系统不易维护。
  4. 对结果集解析存在硬编码(查询列名),sql 变化导致解析代码变化,系统不易维护,如果能将数据库记 录封装成 pojo 对象解析比较方便。

三、mybatis环境搭建

接下来,我们做一个mybatis的小demo,整体上感受一下mybatis的使用过程。

1. 前期准备

① 创建一个maven工程

在这里插入图片描述
在这里插入图片描述

② 创建一个数据库,供我们实验使用:

在这里插入图片描述
新建一张表:

  1. CREATE TABLE `user` (
  2. `id` INT ( 11 ) NOT NULL auto_increment,
  3. `username` VARCHAR ( 32 ) NOT NULL COMMENT '用户名称',
  4. `birthday` datetime DEFAULT NULL COMMENT '生日',
  5. `sex` CHAR ( 1 ) DEFAULT NULL COMMENT '性别',
  6. `address` VARCHAR ( 256 ) DEFAULT NULL COMMENT '地址',
  7. PRIMARY KEY ( `id` )
  8. ) ENGINE = INNODB DEFAULT CHARSET = utf8;

插入一些内容:

  1. INSERT INTO `user` ( `id`, `username`, `birthday`, `sex`, `address` )
  2. VALUES
  3. ( 41, '刘帅帅', '2018-02-27 17:47:08', '男', '菏泽' ),
  4. ( 42, '刘伟佳', '2018-03-02 15:09:37', '男', '青岛' ),
  5. ( 43, '李萌萌', '2018-03-04 11:34:34', '女', '济南' ),
  6. ( 45, '李美美', '2018-03-04 12:04:06', '女', '滨州' ),
  7. ( 46, '外星人', '2018-03-07 17:37:26', '男', '火星' ),
  8. ( 48, '歪比巴卜', '2018-03-08 11:44:00', '女', '三体' );

在这里插入图片描述

2. 搭建mybatis开发环境

① 导入依赖

我们在maven工程中导入依赖,并把项目的打包方式改为jar:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.veeja</groupId>
  5. <artifactId>day01_01mybatis</artifactId>
  6. <version>1.0-SNAPSHOT</version>
  7. <packaging>jar</packaging>
  8. <dependencies>
  9. <dependency>
  10. <groupId>org.mybatis</groupId>
  11. <artifactId>mybatis</artifactId>
  12. <version>3.4.5</version>
  13. </dependency>
  14. <dependency>
  15. <groupId>mysql</groupId>
  16. <artifactId>mysql-connector-java</artifactId>
  17. <version>5.1.6</version>
  18. </dependency>
  19. <dependency>
  20. <groupId>log4j</groupId>
  21. <artifactId>log4j</artifactId>
  22. <version>1.2.12</version>
  23. </dependency>
  24. <dependency>
  25. <groupId>junit</groupId>
  26. <artifactId>junit</artifactId>
  27. <version>4.10</version>
  28. </dependency>
  29. </dependencies>
  30. </project>

② 创建User类:

  1. package com.veeja.domain;
  2. import java.io.Serializable;
  3. import java.util.Date;
  4. public class User implements Serializable {
  5. private Integer id;
  6. private String username;
  7. private Date birthday;
  8. private String sex;
  9. private String address;
  10. public Integer getId() {
  11. return id;
  12. }
  13. public void setId(Integer id) {
  14. this.id = id;
  15. }
  16. public String getUsername() {
  17. return username;
  18. }
  19. public void setUsername(String username) {
  20. this.username = username;
  21. }
  22. public Date getBirthday() {
  23. return birthday;
  24. }
  25. public void setBirthday(Date birthday) {
  26. this.birthday = birthday;
  27. }
  28. public String getSex() {
  29. return sex;
  30. }
  31. public void setSex(String sex) {
  32. this.sex = sex;
  33. }
  34. public String getAddress() {
  35. return address;
  36. }
  37. public void setAddress(String address) {
  38. this.address = address;
  39. }
  40. @Override
  41. public String toString() {
  42. return "User{" +
  43. "id=" + id +
  44. ", username='" + username + '\'' +
  45. ", birthday=" + birthday +
  46. ", sex='" + sex + '\'' +
  47. ", address='" + address + '\'' +
  48. '}';
  49. }
  50. }

③ 编写持久层接口IUserDao

  1. package com.veeja;
  2. import com.veeja.domain.User;
  3. import java.util.List;
  4. /** * 用户的持久层接口 */
  5. public interface IUserDao {
  6. /** * 查询所有的用户 * * @return */
  7. List<User> findAll();
  8. }

④ 编写sqlMapConfig.xml配置文件:

在这里插入图片描述

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
  3. <!--mybatis的主配置文件-->
  4. <configuration>
  5. <!--配置环境-->
  6. <environments default="mysql">
  7. <!--配置mysql的环境-->
  8. <environment id="mysql">
  9. <!--配置事务的类型-->
  10. <transactionManager type="JDBC"></transactionManager>
  11. <!--配置数据源(连接池)-->
  12. <dataSource type="POOLED">
  13. <!--配置连接数据库的4个基本信息-->
  14. <property name="driver" value="com.mysql.jdbc.Driver"/>
  15. <property name="url" value="jdbc:mysql://localhost:3306/mybatisdatabase"/>
  16. <property name="username" value="root"/>
  17. <property name="password" value="0000"/>
  18. </dataSource>
  19. </environment>
  20. </environments>
  21. <!--指定映射配置文件的位置,映射文件指的是每个dao独立的配置文件-->
  22. <mappers>
  23. <mapper resource="com/veeja/dao/IUserDao.xml"/>
  24. </mappers>
  25. </configuration>

⑤ 编写持久层接口的映射文件 IUserDao.xml:

注意:
创建位置:必须和持久层接口在相同的包中。
名称:必须以持久层接口名称命名文件名,扩展名是.xml

在这里插入图片描述

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.veeja.dao.IUserDao">
  4. <!-- 配置查询所有的操作 -->
  5. <select id="findAll" resultType="com.veeja.domain.User">
  6. select * from user
  7. </select>
  8. </mapper>

总结

接下来我们总结一下,搭建一个mybatis的环境需要做些什么?

  1. 创建一个maven工程并且导入依赖;
  2. 创建实体类和DAO接口
  3. 创建mybatis的主配置文件,SqlMapConfig.xml
  4. 创建映射配置文件,IUserDao.xml

这里面有几个注意事项:
第一个:创建IUserDao.xml 和 IUserDao.java时名称是为了和我们之前的知识保持一致。
在Mybatis中它把持久层的操作接口名称和映射文件也叫做:Mapper
所以:IUserDao 和 IUserMapper是一样的
第二个:在idea中创建目录的时候,它和包是不一样的
包在创建时:com.itheima.dao它是三级结构
目录在创建时:com.itheima.dao是一级目录
第三个:mybatis的映射配置文件位置必须和dao接口的包结构相同
第四个:映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
第五个:映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名

当我们遵从了第三,四,五点之后,我们在开发中就无须再写dao的实现类。

3. 测试我们的demo

①log4j的配置文件

首先导入log4j的配置文件,在resources文件夹下创建文件:log4j.properties
在这里插入图片描述
内容如下:

  1. # Set root category priority to INFO and its only appender to CONSOLE.
  2. #log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
  3. log4j.rootCategory=debug, CONSOLE, LOGFILE
  4. # Set the enterprise logger category to FATAL and its only appender to CONSOLE.
  5. log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
  6. # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
  7. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
  8. log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
  9. log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
  10. # LOGFILE is set to be a File appender using a PatternLayout.
  11. log4j.appender.LOGFILE=org.apache.log4j.FileAppender
  12. log4j.appender.LOGFILE.File=d:\axis.log
  13. log4j.appender.LOGFILE.Append=true
  14. log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
  15. log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

② 测试入口:

  1. package com.veeja.test;
  2. import com.veeja.dao.UserDaoImpl;
  3. import com.veeja.domain.User;
  4. import org.apache.ibatis.io.Resources;
  5. import org.apache.ibatis.session.SqlSession;
  6. import org.apache.ibatis.session.SqlSessionFactory;
  7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  8. import java.io.IOException;
  9. import java.io.InputStream;
  10. import java.util.List;
  11. /** * mybatis的入门案例使用main函数执行 */
  12. public class MybatisTest {
  13. /** * 入门案例 */
  14. public static void main(String[] args) throws Exception {
  15. // 1. 读取配置文件
  16. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  17. // 2. 创建一个SqlSessionFactory工厂
  18. SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
  19. SqlSessionFactory factory = builder.build(in);
  20. // 3. 使工厂生产SQLSession对象
  21. SqlSession session = factory.openSession();
  22. // 4. 使用SQLSession创建Dao接口的代理对象(动态代理)
  23. IUserDao userDao = session.getMapper(IUserDao.class);
  24. // 5. 使用代理对象执行方法
  25. List<User> users = userDao.findAll();
  26. for (User user : users) {
  27. System.out.println(user);
  28. }
  29. // 6. 释放资源
  30. session.close();
  31. in.close();
  32. }
  33. }

③ 运行结果

运行一下,结果符合我们预期。
在这里插入图片描述

总结

我们再总结一下刚才在测试类里面我们都做了什么。
第一步:读取配置文件
第二步:创建SqlSessionFactory工厂
第三步:创建SqlSession
第四步:创建Dao接口的代理对象
第五步:执行dao中的方法
第六步:释放资源


四、使用注解

我们发现,这样好像还是很麻烦,还要写xml文件,我们在上面的概述中提到,mybatis可以使用xml或者注解的方式来进行配置。接下来我们演示一下使用注解的配置方式。

我们新建一个maven工程。
在这里插入图片描述
为了方便,我们把上个项目中的src下的main和test文件夹以及pom.xml文件直接复制到新的项目中去。
在这里插入图片描述

我们到底怎么样使用注解呢?

既然我们使用注解,那么上面的一些xml配置文件就没什么用了。
IUserDao.xml文件我们就可以直接删除了。
在这里插入图片描述
然后在我们的UserDaoImpl.java类的相应方法上,我们写上一些注解:

  1. /** * 用户的持久层接口 */
  2. public interface IUserDao {
  3. /** * 查询所有的用户 * * @return */
  4. @Select("select * from user")
  5. List<User> findAll();
  6. }

但是这样有一个问题,我们在SqlMapConfig.xml中有一个mapper,指定了配置文件的位置,
在这里插入图片描述
那么现在这个配置文件没有了,我们该怎么办呢?
如果是注解的方式我们应该使用class属性, 而不是resource属性,也就是:

  1. <mappers>
  2. <mapper class="com.veeja.dao.IUserDao"/>
  3. </mappers>

我们按照上面的测试类继续运行一遍,还是完全没有问题的。
在这里插入图片描述
我们可以发现,这样的方式会简单一些。

我们稍微总结一下使用注解的方式:
UserDaoImpl.xml移除,在dao接口的方法上使用@Select注解,并且指定SQL语句。
同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名。


五、写Dao实现类

我们在实际开发中,都是越简便越好,所以都是采用不写dao实现类的方式,不管使用XML还是注解配置。
但是Mybatis它是支持写dao实现类的。 接下来我们演示一下。

首先创建一个新的工程:
在这里插入图片描述
我们还是把第一个工程中的main和test直接复制到新的项目中来。还要复制pom.xml中的配置进来
在这里插入图片描述
接下来我们在dao文件夹下新建一个包impl,并且添加一个新的IUserDao的实现类UserDaoImpl
在这里插入图片描述
我们要在Dao的实现类中添加一下代码:

  1. public class UserDaoImpl implements IUserDao {
  2. private SqlSessionFactory factory;
  3. /** * 覆写构造参数 * @param factory */
  4. public UserDaoImpl(SqlSessionFactory factory) {
  5. this.factory = factory;
  6. }
  7. public List<User> findAll() {
  8. //1.使用工厂创建SQLSession对象
  9. SqlSession session = factory.openSession();
  10. //2. 使用session执行查询方法
  11. // 为了定位这个方法,使用了namespace.function的方式。
  12. List<User> users = session.selectList("com.veeja.dao.IUserDao.findAll");
  13. session.close();
  14. //3.返回查询结果
  15. return users;
  16. }
  17. }

我们在测试的时候需要作出一点改变,我们的dao是需要一个factory的,我们应该传给它,而且不需要session了:

  1. public class MybatisTest {
  2. /** * 入门案例 */
  3. public static void main(String[] args) throws Exception {
  4. // 1. 读取配置文件
  5. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  6. // 2. 创建一个SqlSessionFactory工厂
  7. SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
  8. SqlSessionFactory factory = builder.build(in);
  9. /******************************************************/
  10. // 3. 使用工厂创建dao对象
  11. IUserDao userDao = new UserDaoImpl(factory);
  12. /******************************************************/
  13. // 4. 使用代理对象执行方法
  14. List<User> users = userDao.findAll();
  15. for (User user : users) {
  16. System.out.println(user);
  17. }
  18. // 5. 释放资源
  19. in.close();
  20. }
  21. }

运行结果完全符合预期:
在这里插入图片描述
但是这样的写法毫无意义,增加了我们开发的任务量,但是需要注意的上面就是在Dao的实现中为了定位相应 的方法,使用了namespace和方法名的方式。


六、分析

1. mybatis入门案例中设计模式的分析

在这里插入图片描述

2. 自定义mybatis的分析

mybatis在使用代理Dao的方式实现增删改查时做什么事呢?
只有两件事,一个是创建代理对象,一个是在代理对象中调用selectList()方法,而里面是具体怎么执行的呢?看如下的图示:
在这里插入图片描述

3. 创建代理对象的分析

在这里插入图片描述


END.

发表评论

表情:
评论列表 (有 0 条评论,713人围观)

还没有评论,来说两句吧...

相关阅读

    相关 mybatis入门()

    什么是 MyBatis ? MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数

    相关 Mybatis):入门

    > Mybatis应该对于任何用Java的人来说都不陌生,以前对于知识有些没有系统性的整理和学习,所以这里把自己当做小白,再次学习下Mybatis。 在此,多说点没用的。学习

    相关 Mybatis入门

    【Mybatis产生背景】 我们以前是用原始的JDBC程序进行对数据库的操作的,但是会出现一系列的问题,小编在这里就进行总结一下。 1.环境    java环境: