MyBatis

比传统的方式更加方便,但是技术没有高低之分;

mybatis是一个版Orm的框架,他内部封装了JDBC;

开发时候只需要关注sql语句本身,不需要花费精力去加载驱动,创建链接,创建statement等繁琐过程。

优点

  1. 基于sql编程,灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在xml中。解除了代码和sql语句的耦合度,便于统一管理,提供xml标签,支持编写动态sql语句,可以重用高。
  2. 与jdbc比,减少了50%的代码量,消除了大量的JDBC大量沉余的代码,不需要手动开关链接。
  3. 与数据库具有很好的兼容性
  4. 能和spring很好的集成
  5. 提供映射标签,支持与数据库的orm字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

缺点:

  1. 注重于sql本身,当子段多,关联表多时,对开发人员编写sql语句有一定功底。
  2. sql语句依赖于数据库,导致数据库移植性差,不能随意更改数据库。

mybatis框架适合场景:

  1. 适合于dao层

    ​ 如果安装标准来的话 那么

    ​ bin —> binImpl

     dao --> daoImpl  mybatis中将dao  改成**mapper.java
    
  1. 对性能要求比较高的话,或者需求比较多且改动较多的情况之下适用mybatis

简单介绍完了,开始重头戏

第一步,先拿到数据库,这里提供一个实例数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
create database if not exists MyBatis_stu default character set utf8 collate utf8_bin; 

use MyBatis_stu ;

create table if not exists classinfo(
cid int primary key auto_increment,
cname varchar(100) not null unique comment '班级编号'
)ENGINE=InnoDB auto_increment=101 default charset=utf8 collate=utf8_bin;

create table if not exists stuinfo (
sid int primary key auto_increment,
sname varchar(100) not null comment '学生姓名',
cid int comment '所在班级编号',
tel varchar(15) unique comment '联系方式',
addr varchar(100) comment '家庭住址',
constraint FK_stuinfo_cid foreign key(cid) references classinfo(cid)
)ENGINE=InnoDB auto_increment=101 default charset=utf8 collate=utf8_bin;

这一步,我觉得不要多说了,毕竟你学java到现在,这一步还是没看懂的话,我觉得你可以准备考虑考虑其他路了。

==第二步前台条件,你要创建好一个maven项目,并导入相关依赖,别告诉我你忘记了maven工程如何创建了?==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<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">
<modelVersion>4.0.0</modelVersion>

<groupId>com.xh</groupId>
<artifactId>Maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Maven</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>

<!--导入maven链接,让maven去下载
https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.8</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.2</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

第二步,根据我们的数据库创建Bean类,什么?你告诉我你不知道什么事Bean类?额,你该恶补一下java了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class ClassInfo {
private Integer cid;
private String cname;

public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((cid == null) ? 0 : cid.hashCode());
result = prime * result + ((cname == null) ? 0 : cname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ClassInfo other = (ClassInfo) obj;
if (cid == null) {
if (other.cid != null)
return false;
} else if (!cid.equals(other.cid))
return false;
if (cname == null) {
if (other.cname != null)
return false;
} else if (!cname.equals(other.cname))
return false;
return true;
}
@Override
public String toString() {
return "ClassInfo [cid=" + cid + ", cname=" + cname + "]";
}
//记得这里我的需要创建的构造方法,你可以选择跟我也可以选择不跟
public ClassInfo( String cname) {
this.cname = cname;
}

public ClassInfo(Integer cid, String cname) {
super();
this.cid = cid;
this.cname = cname;
}

public ClassInfo() {
super();
}
}

==注意,这个类,我实际上在本篇没用上,我会在下篇才用到,你可以自行选择创建或者不创建==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
public class StudentInfo {

private Integer sid;//学生id
private String sname;//学生姓名
private Integer cid; //外键管理,类id
private String tel; //电话号码
private String addr;//地址

public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((addr == null) ? 0 : addr.hashCode());
result = prime * result + ((cid == null) ? 0 : cid.hashCode());
result = prime * result + ((sid == null) ? 0 : sid.hashCode());
result = prime * result + ((sname == null) ? 0 : sname.hashCode());
result = prime * result + ((tel == null) ? 0 : tel.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
StudentInfo other = (StudentInfo) obj;
if (addr == null) {
if (other.addr != null)
return false;
} else if (!addr.equals(other.addr))
return false;
if (cid == null) {
if (other.cid != null)
return false;
} else if (!cid.equals(other.cid))
return false;
if (sid == null) {
if (other.sid != null)
return false;
} else if (!sid.equals(other.sid))
return false;
if (sname == null) {
if (other.sname != null)
return false;
} else if (!sname.equals(other.sname))
return false;
if (tel == null) {
if (other.tel != null)
return false;
} else if (!tel.equals(other.tel))
return false;
return true;
}
@Override
public String toString() {
return "StudentInfo [sid=" + sid + ", sname=" + sname + ", cid=" + cid + ", tel=" + tel + ", addr=" + addr
+ "]";
}
public StudentInfo(Integer sid, String sname, Integer cid, String tel, String addr) {
super();
this.sid = sid;
this.sname = sname;
this.cid = cid;
this.tel = tel;
this.addr = addr;
}
public StudentInfo() {
super();
}
}

第三步,我们要准备数据库配置文件

这个自行确定,账号密码请你更改为自己安装数据库的账号密码,我给出我的实例==db.properties==

1
2
3
4
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis_stu?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useOldAliasMetadataBehavior=true
username=root
password=123456

第四步,创建mybatis配置文件

有了上边三步的基础之后,我们需要配置mybatis-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?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>
<!-- 引入配置文件 请好好的看我 我是db.properties -->
<properties resource="db.properties"></properties>
<!-- 配置环境变量 development :开发环境 work :工作环境 -->

<environments default="development">
<environment id="development">
<!-- 事务管理 -->
<transactionManager type="JDBC" />
<!-- 配置数据库连接信息 POOLED UNPOOLED -->
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>

<mappers>
<!-- 加载mapper指向位置 -->
<mapper resource="mapper/ClassInfoMapper.xml" />
<mapper resource="mapper/StudentInfoMapper.xml"></mapper>

</mappers>


</configuration>

至此,第四步就完成。

第五步,配置映射

我想说的这上面的每一步都很重要,但是这一步也很重要,我们将相关SQL语句全部写在这里,这一步,我们其实可以说是直接对数据库进行操作,我的理解是这样的,但是不同的人有不同的理解,我也不能去把我的思想强加给别人,对吧?

==对了,如果你是初学者,我推荐你了解一下我在本项目的注释==
==ClassInfoMapper.xml==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?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 :命名空间 ,就是用来避免命名冲突的,同一个命名空间下面都不能出现相同的id
时间上这个就是指向 "ClassInfo.findAll" 测试类的这个属性的ClassInfo代表命名空间,findAll代表id
-->
<mapper namespace="ClassInfo">


<!-- 写insert delete update select 语句 每一个语句都有一个id,到时候通过命名空间.id 来获取对应的sql语句执行
通过paramenterType 属性来指定这个sql执行语句的参数 通过resultType属性指定这个sql语句后返回值的类型,是每条结果对应的类型 -->
<select id="findAll" resultType="com.xh.mybatis.bean.ClassInfo">
select cid,cname from classinfo;
</select>

<!-- 假设我们要查询某单一的字段,我们需要的操作是如下 -->
<select id="find" resultType="com.xh.mybatis.bean.ClassInfo">
select cid,cname from classinfo
where cname=#{cname};
</select>

<insert id="add" parameterType="com.xh.mybatis.bean.ClassInfo">
<!--#{} 采用预编译的方式 ${} 采用字符串拼接的方法 -->
insert into classinfo values(0,#{cname});
</insert>

<!-- 模糊查询 vague '%${parameters}%' %#{parameters}%此时这个语句是有问题的,不能这么写 应该是 '%#{parameters}%'
_${parameters}这种模糊查询也是可以的,但是没有%那么灵活,不过你觉得你使用哪个舒服就使用哪个 -->
<select id="findByVague"
resultType="com.xh.mybatis.bean.ClassInfo">
select cid,cname from classinfo where cname like
'_${parameters}';
</select>

<!--更新表中的数据 -->
<update id="update"
parameterType="com.xh.mybatis.bean.ClassInfo">
update classinfo set cname = #{cname} where cid =
#{cid};
</update>

<!-- 删除表中的数据 -->
<delete id="delete"
parameterType="com.xh.mybatis.bean.ClassInfo">
delete from classinfo where cid = #{cid};
</delete>
</mapper>

另一个文件StudentInfoMapper.xml我不会在本篇使用,故而我不在本篇展示,如果你感兴趣的话,请查看下篇。

第六步,测试类的编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package com.xh.mybatis;

import java.io.IOException;
import java.io.InputStream;

import java.util.List;

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 org.junit.jupiter.api.Test;


import com.xh.mybatis.bean.ClassInfo;

public class MyTest {

/**
* classinfo中的所有的值
* @throws IOException
*/
@Test
public void test1() throws IOException {

try (InputStream reader = Resources.getResourceAsStream("mybatis-config.xml")
){
//创建sqlSession工厂

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
System.out.println("-----------");
//从sqlsession工厂中获取一个sql会话
SqlSession sqlSession = sqlSessionFactory.openSession();

//通过这个回话执行与sql语句
//将从表中查询的多条数据以作为对象的方式添加到list中
List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findAll");
//遍历list中的所有的值
cls.forEach(System.out::println);
sqlSession.close();
}
}

/**
* 在classinfo表中添加值 ,非动态添加
* @throws IOException
*/
@Test
public void test2() throws IOException {
try (InputStream reader = Resources.getResourceAsStream("mybatis-config.xml")){
//创建sqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

SqlSession sqlSession = sqlSessionFactory.openSession();

//通过这个回话执行与sql语句,
/**
* 这里的new ClassInfo对象是由于我们创建的表是主键存在主键自增,故而在构造方法中不需要添加cid
* 我们可以选择几种方式,这边我们对构造方法可以进行多种构造,让构造方法去选择添加,也可以直接用全部构造
* 不够就是我们需要对构造方法进行置空处理
*/
int result = sqlSession.insert("ClassInfo.add",new ClassInfo("相关"));
System.out.println(result);
sqlSession.commit();
sqlSession.close();
}
}

/**
* ClassInfo表中
* mybatis查询某数据库中某个值
* @throws IOException
*/
@Test
public void test3() throws IOException {
InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
//创建SqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

SqlSession sqlSession = sqlSessionFactory.openSession();

//我们可以查看到当前查到的对象可以被查出来
//ClassInfo obj = sqlSession.selectOne("ClassInfo.find",new ClassInfo("四班"));
//ClassInfo.find表示调用Mybatis中的com.xh.bean.ClassInfo下的id=find的sql语句
//如果我们使用的是MVC架构进行开发,这个语句应该是属于serviceImpl层调用dao接口的时候
ClassInfo obj = sqlSession.selectOne("ClassInfo.find","四班");
//查找单个
//int result = sqlSession.selectOne("Classinfo.find","四班");
System.out.println(obj);
sqlSession.commit();
sqlSession.close();
}

/**
* 使用模糊查询classInfo中的数据
* 没做动态查询
* @throws IOException
*/
@Test
public void test4() throws IOException {
InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
//创建sqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
System.out.println("-----------");
//从sqlsession工厂中获取一个sql会话
SqlSession sqlSession = sqlSessionFactory.openSession();

//通过这个回话执行与sql语句
//将从表中查询的多条数据以作为对象的方式添加到list中
List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findByVague","班");
//遍历list中的所有的值
cls.forEach(System.out::println);
sqlSession.commit();
sqlSession.close();
}

/**
* 更新表中数据,先从简单的开始,ClassInfo表中的数据
* @throws IOException
*/
@Test
public void test5() throws IOException {
InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
//创建sqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
System.out.println("-----------");
//从sqlsession工厂中获取一个sql会话
SqlSession sqlSession = sqlSessionFactory.openSession();

//通过这个回话执行与sql语句
//将从表中查询的多条数据以作为对象的方式添加到list中
ClassInfo obj = new ClassInfo();

obj.setCid(1);
obj.setCname("一班");

int result = sqlSession.update("ClassInfo.update",obj);
if(result > 0) {
System.out.println("更新成功");
}else {
System.out.println("更新失败");
}

List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findAll");
//遍历list中的所有的值
cls.forEach(System.out::println);

//注意在开启事务的情况下,你不提交数据库是查不到值的
sqlSession.commit();

sqlSession.close();
}

/**
* 删除
* @throws IOException
*/

@Test
public void test6() throws IOException {

InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
//创建sqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

//从sqlsession工厂中获取一个sql会话
SqlSession sqlSession = sqlSessionFactory.openSession();

List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findAll");

System.out.println("删除之前的数据");
cls.forEach(System.out::println);
/*
* ClassInfo obj = new ClassInfo(); obj.setCid(7);
*/
int result = sqlSession.delete("ClassInfo.delete",8);
if(result > 0) {
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
//注意在开启事务的情况下,你不提交数据库是查不到值的
sqlSession.commit();

System.out.println("删除之后的数据");
List<ClassInfo> cls1 = sqlSession.selectList("ClassInfo.findAll");
//遍历list中的所有的值
cls1.forEach(System.out::println);

sqlSession.close();

}

//至此,上边对mybatis的简单操作到此结束
}

mybatis 注意事项:

1
### #{} 和 ${} 的区别

注意:#{}是预编译处理,${}是字符替换

注意:#{}会在mybatis运行的过程中替换为?,调用PreparedStatement的set方法来赋值。

mybatis 在处理$()会将他替换为变量的值。

多使用#{}可以防止sql注入,提高系统安全性。

mybatis 推荐还是使用分页插件

一般mybatis是使用RowBounds对象进行分页,他是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

分页插件的原理是,在mybatis提供的接口,实现自定义插件,在将插件的拦截方法内拦截执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页查询。

如果使用mysql的limit的话会可能会出现数据丢失,索引失效等错误。

动态查询和动态添加以及动态修改

接上一节,注意本博客所有的代码都是建立在上一讲之上的,如果你没有上一讲的配置,这一讲代码我推荐你还是看看,直接搭建环境需要你有上一讲配置完毕,否则会出现许多错误,另外本篇并没有完成Mybatis动态SQL拼接的全部,只是举例一部分进行说明,我们在工作上或者实际生活中使用Mybatis,也是给我自己记录笔记,将来可以进行重构,然后慢慢完善。

废话不多说,我们开始:

第一步,完善上一篇没完善的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
public class StudentInfo {

private Integer sid;//学生id
private String sname;//学生姓名
private Integer cid; //外键管理,类id
private String tel; //电话号码
private String addr;//地址

//添加一个多值传入的方法 在实体类中创建一个List用于存放要删除的sid
private List<Integer> sidList;


public List<Integer> getSidList() {
return sidList;
}
public void setSidList(List<Integer> sidList) {
this.sidList = sidList;
}



public StudentInfo(List<Integer> sidList) {
super();
this.sidList = sidList;
}

public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((addr == null) ? 0 : addr.hashCode());
result = prime * result + ((cid == null) ? 0 : cid.hashCode());
result = prime * result + ((sid == null) ? 0 : sid.hashCode());
result = prime * result + ((sname == null) ? 0 : sname.hashCode());
result = prime * result + ((tel == null) ? 0 : tel.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
StudentInfo other = (StudentInfo) obj;
if (addr == null) {
if (other.addr != null)
return false;
} else if (!addr.equals(other.addr))
return false;
if (cid == null) {
if (other.cid != null)
return false;
} else if (!cid.equals(other.cid))
return false;
if (sid == null) {
if (other.sid != null)
return false;
} else if (!sid.equals(other.sid))
return false;
if (sname == null) {
if (other.sname != null)
return false;
} else if (!sname.equals(other.sname))
return false;
if (tel == null) {
if (other.tel != null)
return false;
} else if (!tel.equals(other.tel))
return false;
return true;
}
@Override
public String toString() {
return "StudentInfo [sid=" + sid + ", sname=" + sname + ", cid=" + cid + ", tel=" + tel + ", addr=" + addr
+ "]";
}
public StudentInfo(Integer sid, String sname, Integer cid, String tel, String addr) {
super();
this.sid = sid;
this.sname = sname;
this.cid = cid;
this.tel = tel;
this.addr = addr;
}
public StudentInfo() {
super();
}
}

实体bean类,作为我们mybatis的映射文件,==注意,本篇和上篇都是简单的进行Mybatis的理解,在正式生产环境会有所差别==,本文档并没有十分规范的按照MVC模式进行,故而请各位体谅。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?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 :命名空间 ,就是用来避免命名冲突的,同一个命名空间下面都不能出现相同的id -->
<mapper namespace="StudentInfo">

<!-- mybatis-config.xml 中 <typeAlias type="com.someapp.model.User" alias="User"/> -->

<!-- 写insert delete update select 语句 每一个语句都有一个id,到时候通过命名空间.id 来获取对应的sql语句执行
通过paramenterType 属性来指定这个sql执行语句的参数 通过resultType属性指定这个sql语句后返回值的类型,是每条结果对应的类型 -->

<select id="findAll"
resultType="com.xh.mybatis.bean.StudentInfo">
select sid,sname,cname,tel,addr from classinfo c, stuinfo s
where c.cid = s.cid order by sid asc;
</select>

<!-- 让我们对具体多个值进行查找 -->
<select id="findByValue"
resultType="com.xh.mybatis.bean.StudentInfo">
select sid,sname,tel,addr from stuinfo
<!-- 动态SQL之前,我们先把最艰简单的sql语句添加上来 注意,在条件语句上,我们必须来一个一定成立的条件,方便我们对数据进行读取和判断,或者你确定了用户一定会输入值,否则不要轻易在这里留坑 -->

where sid != 0

<if test="sname != null">
and sname = #{sname}
</if>
<!-- 注意,我这边缺一点东西,就是判断的时候,我们会有一个判断是否存在,的语句,如果存在多余的我还要将其分离出来 注意正确的sql语句书写
and tel = #{tel} , addr = #{addr}是错误的写法 -->
<if test="tel != null and addr != null">
and tel = #{tel} and addr = #{addr}
</if>
order by sid asc;
</select>


<!-- 我觉得动态添加其实没必要,虽然我寻思也有,但是我还是觉得,动态添加真的没必要,毕竟这特么有点反人类,我寻思,让你添加数据,你特么 老老实实给我把数据填写完毕不就行了吗?
还有就是,我们可以在业务层直接处理,在前端传数据过来,我们就可以判断然后将没传的值置空处理 如果你非要做,我给你这个参考一下 数据库支持多行插入
<insert id="insertTable" useGeneratedKeys="true" keyProperty="id" parameterType
= "com.***">
insert into table (username, password, email, bio) values
<foreach item="item" collection="list" separator=",">
(#{item.username}, #{item.password},
#{item.email}, #{item.bio})
</foreach>
</insert> -->
<insert id="add" parameterType="com.xh.mybatis.bean.StudentInfo">
<!--#{} 采用预编译的方式 ${} 采用字符串拼接的方法 -->
insert into stuinfo values(0,#{sname},#{cid},#{tel},#{addr});
</insert>


<!--接下来就是我们的删除操作了,这个就很简单了,动态删除? 得了吧,我这边给个思路,但是我不做,也就是一次传多个值,然后删除多个值,
1 delete from table where sid in( ${sid} ) 这也是一种方式

<select id="deleteByIds" parameterType="Integer">
delete from accounts where id in
<foreach collection="ids" open="(" close=")"
separator="," item="id"> #{id}
</foreach>
</select>

<delete id="deleteValue"
parameterType="com.xh.mybatis.bean.StudentInfo"> delete from stuinfo where
sid != 0 and sid = #{sid};
</delete> -->

<delete id="deleteValue"
parameterType="com.xh.mybatis.bean.StudentInfo">
delete from stuinfo where cid != 0 and sid = #{sid};
</delete>

<!-- 重头戏来了,我们有些时候会涉及到改操作,但是改操作只对用户的某一个数据进行更改 也可能对多个数据进行更改,故而我们需要判断用户传过来的数据,这个时候就很重要了 -->

<update id="update"
parameterType="com.xh.mybatis.bean.StudentInfo">
update stuinfo set
<if test="sname != null">
sname = #{sname}
</if>
<if test="cid != null">
, cid = #{cid}
</if>
<if test="tel != null">
, tel = #{tel}
</if>
<if test="addr != null">
, addr = #{addr}
</if>
where sid = #{sid};
</update>
</mapper>

这里我们主要使用if语句来判断用户是否传值,如果传值,我们采用mybatis判断进行动态拼接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
public class StuTest {

/**
* 查询表中所有数据,studentInfo,先从一个简单的表开始吧,然后逐层加难
* @throws IOException
*/
@Test
public void test1() throws IOException {
//加载mybatis-config.xml配置文件
InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
//创建sqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = sqlSessionFactory.openSession();
List<StudentInfo> cls = sqlSession.selectList("StudentInfo.findAll");
//遍历list中的所有的值
cls.forEach(System.out::println);
sqlSession.commit();
sqlSession.close();
}

/**
* 多值查询
* @throws IOException
*/
@Test
public void test2() throws IOException {
//加载mybatis-config.xml配置文件
InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
//创建sqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = sqlSessionFactory.openSession();
//多值查询,为了避免我使用new StudentInfo(****)
StudentInfo stu = new StudentInfo();
//注意,这里我就开始使用动态sql进行判断了
stu.setSname("王老五");

//stu.setTel("15973121101");
//stu.setAddr("湖南衡阳");

//我们查询的时候可以是一个值,也可以是多个值,故而我们通常将查到的值存到集合中,至于是哪种集合,你选择
List<StudentInfo> cls = sqlSession.selectList("StudentInfo.findByValue", stu);

//遍历list中的所有的值
cls.forEach(System.out::println);

sqlSession.commit();
sqlSession.close();
}


/**
* 多值添加
* @throws IOException
*/
@Test
public void test3() throws IOException {
//加载mybatis-config.xml配置文件
InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
//创建sqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = sqlSessionFactory.openSession();
//先查询所有数据
List<StudentInfo> cls = sqlSession.selectList("StudentInfo.findAll");
cls.forEach(System.out::println);

StudentInfo stu = new StudentInfo();

stu.setSname("王老五");
stu.setCid(1);
stu.setTel("16682187574");
stu.setAddr("湖南长沙");

int result = sqlSession.insert("StudentInfo.add",stu);
if(result > 0) {
System.out.println("添加成功");
}else {
System.out.println("添加失败");
}

//遍历list中的所有的值
sqlSession.commit();

//插入后提交成功之后再次查询
List<StudentInfo> cls1 = sqlSession.selectList("StudentInfo.findAll");
cls1.forEach(System.out::println);
sqlSession.close();
}

@Test
public void test4() throws IOException {
//加载mybatis-config.xml配置文件
InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
//创建sqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = sqlSessionFactory.openSession();
//在删除之前,我们先查询表中数据
List<StudentInfo> cls = sqlSession.selectList("StudentInfo.findAll");

//遍历list中的所有的值
cls.forEach(System.out::println);

StudentInfo stu = new StudentInfo();

//System.out.println(sidList);
//System.out.println(stu.getSidList());

//你要删除的id号
stu.setSid(8);
int result = sqlSession.delete("StudentInfo.deleteValue",stu);
if(result > 0) {
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}

sqlSession.commit();

List<StudentInfo> cls1 = sqlSession.selectList("StudentInfo.findAll");
//遍历list中的所有的值
cls1.forEach(System.out::println);
sqlSession.close();

}

@Test
public void test5() throws IOException {
//加载mybatis-config.xml配置文件
InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
//创建sqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = sqlSessionFactory.openSession();
//多值查询,为了避免我使用new StudentInfo(****)
StudentInfo stu = new StudentInfo();
//注意,这里我就开始使用动态sql进行判断了
//cid为空只是因为我没查,不要误会。
stu.setSname("王老六"); //StudentInfo [sid=9, sname=王老六, cid=null, tel=16682187574, addr=湖南长沙]
stu.setCid(2); //更改班级编号,前台条件班级必须存在
stu.setSid(9); //更新语句的条件

stu.setTel("15973121103");
stu.setAddr("湖南衡阳");
// 更新后的数据 StudentInfo [sid=9, sname=王老六, cid=null, tel=15973121103, addr=湖南衡阳]
//我们查询的时候可以是一个值,也可以是多个值,故而我们通常将查到的值存到集合中,至于是哪种集合,你选择
int result = sqlSession.update("StudentInfo.update",stu);
if(result > 0) {
System.out.println("更新成功");
}else {
System.out.println("更新失败");
}

List<StudentInfo> cls = sqlSession.selectList("StudentInfo.findByValue", stu);

cls.forEach(System.out::println);
sqlSession.commit();
sqlSession.close();
}
}

mybatis + Spring框架

1
2
3
4
5
6
7
8
9
-- 创建一个简单的数据库
create database mybatis if not exists ;
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;

安装mybatis

1
2
3
4
5
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>

快速上手

1
2
3
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
1
2
3
4
5
6
7
8
9
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean.getObject();
}
}

注意:SqlSessionFactory 需要一个 DataSource(数据源)。这可以是任意的 DataSource,只需要和配置其它 Spring 数据库连接一样配置它就可以了。

假设你定义了一个如下的 mapper 接口:

1
2
3
4
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{userId}")
User getUser(@Param("userId") String userId);
}

那么可以通过 MapperFactoryBean 将接口加入到 Spring 中:

1
2
3
4
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

需要注意的是:所指定的映射器类必须是一个接口,而不是具体的实现类。在这个示例中,通过注解来指定 SQL 语句,但是也可以使用 MyBatis 映射器的 XML 配置文件。

配置好之后,你就可以像 Spring 中普通的 bean 注入方法那样,将映射器注入到你的业务或服务对象中。MapperFactoryBean 将会负责 SqlSession 的创建和关闭。 如果使用了 Spring 的事务功能,那么当事务完成时,session 将会被提交或回滚。最终任何异常都会被转换成 Spring 的 DataAccessException 异常。

使用 Java 代码来配置的方式如下:

1
2
3
4
5
6
7
8
@Configuration
public class MyBatisConfig {
@Bean
public UserMapper userMapper() throws Exception {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory());
return sqlSessionTemplate.getMapper(UserMapper.class);
}
}

要调用 MyBatis 的数据方法,只需一行代码:

1
2
3
4
5
6
7
8
9
10
11
12
public class FooServiceImpl implements FooService {

private final UserMapper userMapper;

public FooServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}

public User doSomeBusinessStuff(String userId) {
return this.userMapper.getUser(userId);
}
}

Mybatis-Spring

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。 最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。

MyBatis-Spring MyBatis Spring Framework Spring Batch Java
2.0 3.5+ 5.0+ 4.0+ Java 8+
1.3 3.4+ 3.2.2+ 2.1+ Java 6+

初始配置文件

1
2
3
4
5
6
7
<?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>

枚举类型配置案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode"/>
</resultMap>

<select id="getUser" resultMap="usermap">
select * from users
</select>
<insert id="insert">
insert into users (id, name, funkyNumber, roundingMode) values (
#{id}, #{name}, #{funkyNumber}, #{roundingMode}
)
</insert>

<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
</resultMap>
<select id="getUser2" resultMap="usermap2">
select * from users2
</select>
<insert id="insert2">
insert into users2 (id, name, funkyNumber, roundingMode) values (
#{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
)
</insert>
</mapper>

mybatis链接数据库的xml书写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--这是一种写法可以将驱动写在类里边,然后通过将依赖注入值@Value-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>

链接mysql链接依赖url

1
2
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>