学习MyBtis之前,需要对一下技术有一定的了解:
MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. MyBatis eliminates almost all of the JDBC code and manual setting of parameters and retrieval of results. MyBatis can use simple XML or Annotations for configuration and map primitives, Map interfaces and Java POJOs (Plain Old Java Objects) to database records.
MyBaits是第一个支持自定义SQL、存储过程和高级映射的类持久层框架。MyBtis消除了几乎所有的JDBC代码、手动设置参数值和查询结果集。MyBatis可以使用简单的XML和注解来配置和映射原始信息,将接口和Java的POJOs(Plain Old Java Object,普通的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.5 ,其发布时间是2020年6月4日。
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.5version>
dependency>
持久化:程序数据再持久状态和瞬时状态转化的机制。
举个栗子:
在程序运行的时候,我们有时候希望保存我们的程序数据,比如用户、密码等信息数据,这个时候,我们就需要将这些程序数据固定下来。
我们知道,程序运行时数据是保存在内存中的。内存速度快,但价格高昂,且断电易失,而硬盘速度慢,但价格低廉,即使断电数据也不会丢失,取长补短,那我们就可以将内存中的程序数据保存到硬盘中,在需要的时候再取出来。存取数据的过程就叫持久化。
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
- 解耦:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql。
创建数据库mybatis
和表user
,插入测试数据
mysql> CREATE DATABASE mybatis;
Query OK, 1 row affected (0.06 sec)
mysql> USE mybatis
Database changed
mysql> CREATE TABLE user(
-> id INT NOT NULL PRIMARY KEY,
-> name VARCHAR(30) DEFAULT NULL,
-> pwd VARCHAR(30) DEFAULT NULL
-> )ENGINE=InnoDB;
Query OK, 0 rows affected (0.13 sec)
mysql> INSERT INTO user(id,name,pwd)
-> VALUES
-> (1,'狂神','123456'),
-> (2,'张三','123456'),
-> (3,'李四','123456');
Query OK, 3 rows affected (0.02 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> SELECT id,name,pwd FROM user;
+----+--------+--------+
| id | name | pwd |
+----+--------+--------+
| 1 | 狂神 | 123456 |
| 2 | 张三 | 123456 |
| 3 | 李四 | 123456 |
+----+--------+--------+
3 rows in set (0.01 sec)
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.20version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.5version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
dependencies>
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis&useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="mysql"/>
dataSource>
environment>
environments>
configuration>
package com.cap.utils;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
//获取sqlSessionFactory
static{
InputStream inputStream = null;
try {
String resource = "mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
Now that you have a SqlSessionFactory, as the name suggests, you can acquire an instance of SqlSession.
The SqlSession contains absolutely every method needed to execute SQL commands against the database.
*/
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
package com.cap.pojo;
/**
* 实体类
* 这里提一下ORM思想(Object Relational Mapping对象关系映射)
* - 一个实体类对应一个表
* - 实体类的一个对象对应表中的一行记录
* - 对象中的一个成员变量对应一行记录中的一列属性
* @author cap
* @create 2020.06.29.16:25
*/
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;
}
//...省略Getter和Setter方法
}
以前我们都是称之为DAO(Data Access Object数据访问对象),但在MyBatis中我们都是用xml配置文件来映射到我们需要的SQL语句,所以在之后MyBatis的使用中,我们更习惯用Mapping来作为对DAO的替代命名。
package com.cap.dao;
/**
* @author cap
* @create 2020.06.29.17:00
*/
public interface UserDao {
List<User> getUserList();
}
由原来的DaoUserImpl实现类改为现在的一个UserMapping.xml配置文件
<mapper namespace="com.cap.dao.UserDao">
<select id="getUserList" resultType="com.cap.pojo.User">
SELECT * FROM mybatis.user;
select>
mapper>
public class UserDaoTest {
@Test
public void test(){
//第一步:获得sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//方式一:getMapper
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
for(User user : userList){
System.out.println(user);
}
//关闭sqlSession
sqlSession.close();
}
}
java.lang.ExceptionInInitializerError
....
### Error building SqlSession.
### Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence....
可以看到,这个原因主要是因为编码集的问题,将mybatis-config.xml和UserMapping.xml的编码集UTF-8改为UTF8
org.apache.ibatis.binding.BindingException: Type interface com.cap.dao.UserDao is not known to the MapperRegistry.
可以看到,这里说到了对于MapperRegistry来说,它还不认识UserDao接口,其实这是因为我们在mybatis-config.xml添加配置信息的时候,我们除了配置了数据库连接的相关信息,其实还需要配置对于DAO层中的UserMapping.xml,这样MyBatis才能从mybatis-config.xml中去读取到UserMapping中相关的SQL语句和UserDao接口
在mybatis-config.xml中新添加mappers标签来配置UserMapping.xml路径
<mappers>
<mapper resource="com/cap/dao/UserMapping.xml"/>
mappers>
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>
另一种方式,这种方法了解一下就可,因为他有两个弊端,一是容易出现字面量错误,二是有转型安全问题
@Test
public void test2(){
//第一步:获得sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//方式二:
List<User> userList = sqlSession.selectList("com.cap.dao.UserDao.getUserList");
/*
这种方式不推荐,原因有二
一是容易出现字面量错误
二是原本List
for(User user : userList){
System.out.println(user);
}
//关闭sqlSession
sqlSession.close();
}
为了命名方便,我们将项目原来的UserDao
接口改名为UserMapping
UserMapping
增加一个新方法getUserById()
/**
* 根据id查询用户
* @param id
* @return
*/
User getUserById(int id);
<mapper namespace="com.cap.dao.UserMapping">
<select id="getUserById" resultType="com.cap.pojo.User" parameterType="int">
SELECT * FROM mybatis.user
WHERE id = #{id};
select>
mapper>
id
:对应的接口方法名parameterType
:参数类型resultType
:返回类型,注意这里使用全限定名#()
:指定方法形参名 /**
* 测试查询操作
*/
@Test
public void test3(){
//第一步:获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//第二步:执行,获取结果集
UserMapping mapper = sqlSession.getMapper(UserMapping.class);
User user = mapper.getUserById(2);
System.out.println(user);
sqlSession.close();
}
/**OUTPUT
User{id=2, name='张三', pwd='123456'}
*/
addUser()
/**
* 插入一个新用户
* @param user
*/
int addUser(User user);
<mapper namespace="com.cap.dao.UserMapping">
<insert id="addUser" parameterType="com.cap.pojo.User" >
INSERT INTO mybatis.user(id,name,pwd)
VALUES(#{id},#{name},#{pwd});
insert>
mapper>
注意这里
#()
可以直接使用User中的属性,这样一来就绕开了Getter、Setter,更加方便
/**
* 测试插入操作
*/
@Test
public void test4(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapping mapper = sqlSession.getMapper(UserMapping.class);
//返回的是受影响的行数,大于0说明插入成功
int resultInt = mapper.addUser(new User(5,"李白","123456"));
if(resultInt > 0){
System.out.println("插入成功");
}else{
System.out.println("插入失败");
}
//增删改需要提交事务
sqlSession.commit();
sqlSession.close();
}
/**OUTPUT
插入成功
*/
注意这里需要手动提交事务
对于更新UPDATE、删除DELETE操作来说,步骤都是一样的,先在接口声明变量,然后配置SQL,最后编写测试方法,这里就不再赘述。另外如果接口方法有多个形参,那么就不能使用parameterType,方法见博客Mybatis (ParameterType) 如何传递多个不同类型的参数(注意这篇博客提到的的第一种方法已经不能再使用0
、1
,使用arg0
、arg1
或者使用param1
、param2
)
接口编写模糊查询方法
List<User> getUserLike(String name);
方式一:在UserMapping.xml配置文件中编写SQL语句,附带通配符
<select id="getUserLike" resultType="com.cap.pojo.User" parameterType="String">
SELECT * FROM mybatis.user
WHERE name LIKE "%"#{name}"%";
select>
List<User> userList = mapper.getUserLike("狂");
for(User user : userList){
System.out.println(user);
}
/**OUTPUT
User{id=1, name='狂神', pwd='123456'}
User{id=6, name='狂铁', pwd='123456'}
*/
方式二:调用方法时传入的参数附带通配符
<select id="getUserLike" resultType="com.cap.pojo.User" parameterType="String">
SELECT * FROM mybatis.user
WHERE name LIKE "%"#{name}"%";
select>
List<User> userList = mapper.getUserLike("%狂%");
for(User user : userList){
System.out.println(user);
}
/**OUTPUT
User{id=1, name='狂神', pwd='123456'}
User{id=6, name='狂铁', pwd='123456'}
*/