内容简介
本文是对MyBatis的基础操作方式进行的演示,包括MyBatis环境搭建,以及一些细节知识点。
我们会发现其实各种操作方式的步骤大同小异,因为究其根源它们实现的都是相同的功能。
为了让大家能更好的理解,我们来试着分析一下MyBatis究竟帮我们实现了什么样的功能。
- 连接MySQL数据库的功能
- 连接持久层接口的功能
- 通过映射配置文件的方式
- 通过注解的方式
- 实现持久层接口的功能
- 创建持久层接口实现类
- 使用代理的持久层接口实现类
思维导图
搭建环境
创建Maven工程
- GroupID
- 项目组织唯一的标识符
- 实际对应Java的包的结构,main/Java目录下的目录结构。
- GroupID分为多段,第一段为域,第二段为公司名称等。
- 域:org(非盈利组织)、com(商业公司)、cn(中国组织)
- ArtifactID
- 项目的唯一的标识符
- 实际对应项目的名称,项目根目录的名称。
举例:Apache公司的Tomcat项目
GroupID:org.apache
ArtigactID:tomcat
添加MyBatis坐标
- Maven坐标
- Maven拥有数量非常巨大的构件(jar/war),而任何一个构件都可以使用Maven坐标来获取。maven坐标的元素包括groupId,artifactId,version,package,classifier。
- 引入依赖
- 一旦我们在pom.xml文件中配置好 dependancy标签 中的 groupId标签,artifact标签,verison标签 和classifier标签,maven就会从仓库中寻找相应的构件供我们使用。
- 在pom.xml 文件中,引入4个依赖:
- mybatis(MyBatis框架)
- mysql-connector-java(数据库连接)
- junit (单元测试)
- log4j(日志文件)
1 | <dependencies> |
创建数据库
1 | #创建数据库 |
方法一:映射配置文件
目录结构
- src/main
- java
- cn/water/dao
- UserDao.java(持久层接口)
- cn/water/domain
- User.java(实体类)
- cn/water/dao
- resources
- cn/water/dao
- UserDao.xml(持久层接口的映射配置文件)
- SqlMapConfig.xml(MyBatis主配置文件)
- cn/water/dao
- java
- src/tese
- java
- cn/water/test
- UserTest.java(测试文件)
- cn/water/test
- java
实体类
- 实体类要实现Serializable接口,因为在封装MySQL数据库数据时,运用了代理对象。
- 实体类中的成员变量和MySQL数据库中的列属性保持一致。
User.java
1 | package cn.water.domain; |
持久层接口
- 编写一个操作数据库的抽象方法,但是具体的SQL语句会由持久层接口的映射文件来编写。
UserDao.java
1 | package cn.water.dao; |
映射配置文件
- 映射配置文件:专注于编写SQL语法,一个持久层接口对应一个映射配置文件。
- 创建位置:映射配置文件必须和持久层接口在相同的包中。
- 持久层接口:src/main/java/cn/water/dao/
- 映射配置文件:src/main/resources/cn/water/dao/
- 名称:映射配置文件必须以持久层接口名称命名文件名,扩展名是.xml。
- 持久层接口:UserDao.java
- 映射配置文件:UserDao.xml
- 创建位置:映射配置文件必须和持久层接口在相同的包中。
UserDao.xml
- 语法
- mapper
- namespace:持久层接口的全类名
- select
- id:方法名称
- resultType:返回值类型
- SQL语句
- mapper
- 含义
- findAll方法的位置:cn.water.do.UserDao
- findAll方法的SQL语句:SELECT * FROM user;
- findAll方法的返回值类型:cn.water.domain.User
1 |
|
MyBatis主配置文件
- MyBatis主配置文件:专注于连接数据库,一个映射配置文件对应一个mapper标签。
SqlMapConfig.xml
- configuration
- environments default=”mysql” :环境
- environment id=”mysql” :MySQL环境
- transactionManager type=”JDBC” :事务类型
- dataSource type=”POOLED” :数据库连接池
- property name=”” value=”” :连接数据库的4个基本信息
- environment id=”mysql” :MySQL环境
- mappers
- mapper resource=”” :指定映射配置文件的项目路径
- environments default=”mysql” :环境
1 |
|
测试类
- 加载 MyBatis主配置文件(Resources.getResourceAsStream),获取IO流(InputStream)
- 通过 工厂建造者类(SqlSessionFactoryBuilder),创建 工厂类**(build())
- 通过 工厂类(SqlSessionFactory),生产 SqlSession对象(openSession())
- 通过 Session对象(SqlSession),创建 持久层接口的代理对象(getMapper(UserDao.class))
- 通过 代理对象,执行方法
- 释放资源(SqlSession)(InputStream)
UserTest.java
1 | package cn.water.test; |
运行结果
1 | User{id=41, username='老王', birthday=Tue Feb 27 17:47:08 CST 2018, sex='男', address='北京'} |
设计模式
构建者模式
- 定义:
- 指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。
- 举例
- 计算机是由 OPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、鼠标等部件组装而成的,采购员不可能自己去组装计算机,而是将不同计算机的配置要求告诉计算机销售公司,计算机销售公司安排技术人员去组装计算机,然后再交给要买计算机的采购员。
- 优点
- 各个具体的建造者相互独立,有利于系统的扩展。
- 客户端不必知道产品内部组成的细节,便于控制细节风险。
- 缺点
- 产品的组成部分必须相同,这限制了其使用范围。
- 如果产品的内部变化复杂,该模式会增加很多的建造者类。
1 | InputeStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); |
工厂模式
- 定义
- 定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。
- 举例
- 各种产品有专门的工厂生产。在苹果工厂,我们可以拿到iPhone、iPad和macbook;在华为工厂,我们可以拿到p30,mate20,Matebook。我们不关心产品是如何做的,甚至可以不关心产品的名字(拿到工厂你就拿到了产品)。
- 优点
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
- 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
- 缺点
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
- 区别
- 建造者模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。
1 | SqlSession sqlSession = factory.openSession(); |
代理模式
- 定义
- 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
- 举例
- 购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。
- 优点
- 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
- 代理对象可以扩展目标对象的功能;
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
- 缺点
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
- 增加了系统的复杂度;
1 | List<User> list = dao.findAll(); |
方法二:注解
- 注解可以代替映射配置文件。
目录结构
- src/main
- java
- cn/water/dao
- AnnoUserDao.java(持久层接口)
- cn/water/domain
- AnnoUser.java(持久层)
- cn/water/dao
- resources
- SqlMapConfig.xml(MyBatis主配置文件)
- java
- src/tese
- java
- cn/water/test
- AnnoUserTest.java(测试文件)
- cn/water/test
- java
实体类
AnnoUser.java
1 | package cn.water.domain; |
持久层接口(注解)
- 在持久层接口的抽象方法上添加 @Select注解,并编写SQL语句
AnnoUserDao.java
1 | package cn.water.dao; |
映射配置文件(删除)
MyBatis主配置文件(映射)
- environments 标签中的内容用于连接MySQL数据库无需更改。
- 在 mappers 标签中添加映射
- 方法一:使用class属性,指定被注解的持久层接口的全类名。
- 方法二:使用package标签,指定被注解的持久层接口的包。
SqlMapConfig.xml
1 | <mappers> |
1 | <mappers> |
测试类
AnnoUserTest.java
1 | package cn.water.test; |
运行结果
1 | User{id=41, username='老王', birthday=Tue Feb 27 17:47:08 CST 2018, sex='男', address='北京'} |
方法三:创建持久层接口实现类
目录结构
- src/main
- java
- cn/water/dao
- ImpUserDao.java(持久层接口)
- ImpUserDaoImp.java(持久层接口的实现类)
- ImpUserDao.java(持久层接口)
- cn/water/dao
- cn/water/domain
- ImpUser.java(持久层)
- resources
- cn/water/dao
- ImpUserDao.xml(持久层接口的映射配置文件)
- SqlMapConfig.xml(MyBatis主配置文件)
- java
- src/tese
- java
- cn/water/test
- ImpUserTest.java(测试文件)
- cn/water/test
- java
实体类
ImpUser.java
1 | package cn.water.domain; |
持久层接口
ImpUserDao.java
1 | package cn.water.dao; |
持久层接口实现类(新增)
1 | package cn.water.dao.imp; |
映射配置文件(修改)
ImpUserDao.xml
1 |
|
MyBatis主配置文件(映射)
SqlMapConfig.xml
1 | <mappers> |
测试类(更改)
ImpUserTest.java
1 | package cn.water.test; |
运行结果
1 | User{id=41, username='老王', birthday=Tue Feb 27 17:47:08 CST 2018, sex='男', address='北京'} |
区别
SQL语句
映射配置文件
- 持久层接口
1 | List<UserAnno> findAll(); |
- 映射配置文件
1 | <!-- 配置映射 --> |
持久层接口实现类
- 持久层接口
1 | List<UserAnno> findAll(); |
- 映射配置文件
1 | <!-- 配置映射 --> |
注解
- 持久层接口
1 | "SELECT * FROM user;") ( |
mappers标签
- MyBatis主配置文件
1 | <mappers> |
执行
映射配置文件
- 测试类
1 | /* 1.读取 MyBatis主配置文件 */ |
持久层接口实现类
- 持久层接口实现类
1 | /* 4.Session对象 */ |
- 测试类
1 | /* 1.读取 MyBatis主配置文件 */ |
注解
1 | /* 1.读取 MyBatis主配置文件 */ |
报错
错误一:IllegalArgumentException
错误代码
1 | Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for cn.water.dao.UserImpDao |
错误原因一:SqlSession调用selectList方法的参数错误
1 | <!-- 持久层接口的映射配置文件 --> |
1 | /* 持久层接口的实现类*/ |
错误原因二:MyBatis主配置文件中没有设置mapper标签
1 | <!-- 映射配置文件:使用resource属性指定映射配置文件的位置。 --> |