使用Mybatis的动态Sql实现多表查询

具体实现(student项目)

创建数据库

1
2
3
4
5
6
7
8
9
10
11
create table teacher(
id int(10) primary key auto_increment,
name varchar(20)
);

create table student(
id int(10) primary key auto_increment,
name varchar(20),
age int(3),
tid int(10)
);

数据库情况:

学生表添加外键:

搭建环境

1. 导入相关jar包
2. 准备mybatis.xml全局配置文件(里面利用package标签找那个接口!!!!)
3. 准备student实体类
4. 准备teacher实体类
5. 准备pageInfo分页实体类
6. 准备实现类接口StudentMapper
...

Mybatis实现多表查询方式

多表查询三种方式

1. 业务装配:
    两表单表查询 -- 在业务(service)将查询结果关联
2. 通过Auto Mapping特性
    两表联合查询 -- 通过别名完成映射    
3. 使用Mybatis的resultMap标签进行实现

类中(其他类) 分类

1. 单个对象

2. 集合对象

单表resultMap

resultMap标签(mapper.xml中)

程序员控制sql查询结果与实体类的映射关系
默认:Mybatis使用Auto Mapping特性(resultType属性)
更改:Mybatis使用resultMap属性引用resultMap标签(不写resultType属性)

具体操作

1. 数据库(id和name两列):

2. 实体类(我们用id1和name1区别)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Teacher {
private int id1;
private String name1;

public int getId1() {
return id1;
}
public void setId1(int id1) {
this.id1 = id1;
}
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}

}

3. 在TeacherMapper.xml配置文件中使用resultMap标签:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<mapper namespace="com.bjsxt.mapper.TeacherMapper">

<resultMap type="teacher" id="mymap">
<!-- 主键用id -->
<id column="id" property="id1"/>
<!-- 其他列用result -->
<result column="name" property="name1"/>
</resultMap>

<select id="selAll" resultMap="mymap">
select * from teacher
</select>

</mapper>

单表总结使用

1. 实体类去写需要映射的名称(id和name 实体类就写id1和name1)
2. 配置文件中select里面把resultType改成使用resultMap属性 
    注: resultMap属性值 == resultMap标签的id值
3. 书写resultMap标签
    注: resultMap两个属性一个是类型 一个是和select里面属性匹配的id
         主键使用id标签 其他列用result标签
         里面column写的是数据库的名称 property写的是映射的实体类名称

resultMap实现关联单个对象(N+1方式) association标签

就是先查询出一个表的全部信息 然后根据这个表的信息再查另外一个表的信息(两个表合并)

具体操作

1. 学生数据库的tid是刚才老师id的外键

2. 学生实体类除了自己的属性还要有一个老师的对象

1
2
3
4
5
6
 //只列举了变量
private int id;
private String name;
private int age;
private int tid;
private Teacher teacher; //老师类的对象!!!!!!

3. 学生配置文件(通过association标签把tid给老师的sql语句中当做id)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<mapper namespace="com.bjsxt.mapper.StudentMapper">

<resultMap type="student" id="linahe">

<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
<result column="tid" property="tid"/>
<association property="teacher" select="com.bjsxt.com.TeacherMapper.selById" column="tid"></association>

</resultMap>

<select id="selAll" resultMap="lianhe">
select * from student
</select>

</mapper>

4. 老师配置文件(只写根据id查老师信息的sql语句)

1
2
3
4
5
6
7
<mapper namespace="com.bjsxt.mapper.TeacherMapper">

<select id="selById" resultType="teacher" parameterType="int"> //只需要写好根据id查老师的sql操作
select * from teacher where id=#{id}
</select>

</mapper>

结果分析

图例分析流程:

具体实现过程:

1. 准备老师和学生类(要有老师类对象)
2. 准备老师的配置文件(通过id查询结果)
3. 准备学生的配置文件
    3.1 先写自己的sql语句 -- resultMap属性连接到resultMap标签的id  -- id标签写学生的主键映射 result标签写学生的其他列映射
    3.2 一定要用association标签!!!(column属性把学生的tid拿过来 select去掉老师配置文件的sql语句的方法名一定是全路径!!)

resultMap实现关联集合对象(N+1方式) colloction标签

其实关联 集合对象(老师返回学生的list集合) / 单个对象(学生传老师一个对象) 只是从不同角度来看!!!!!!

具体操作

1. teacher实体类(放的就是list集合)

1
2
3
private int id;
private String name;
private List<Student> list; //list集合返回结果

2. student配置文件(只需要写简单的sql语句让老师传过来id当tid用)

1
2
3
4
5
6
7
<mapper namespace="com.bjsxt.mapper.StudentMapper">

<select id="selByTid" resultType="student" parameterType="int">
select * from student where tid=#{id}
</select>

</mapper>

3. teacher老师配置文件(通过collection标签将id传过去当tid查)

1
2
3
4
5
6
7
8
9
10
11
12
13
<mapper namespace="com.bjsxt.mapper.TeacherMapper">

<resultMap type="teacher" id="mymap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="list" ofType="student" select="com.bjsxt.mapper.StudentMapper.selByTid" column="id"></collection>
</resultMap>

<select id="selAll" resultMap="mymap">
select * from teacher
</select>

</mapper>

结果分析

图例分析流程:

具体实现过程:

1. 准备老师类(要有list集合返回学生类信息)和学生类
2. 准备学生的配置文件(只需要sql语句通过id查所有信息)
3. 准备老师的配置文件
    3.1 通过查询的sql语句去找resultMap标签 然后标签去找学生配置文件的方法查处结果(将id传过去当tid用)

多表resultMap加载集合对象联合查询方式

假设老师1有多个学生(数据库会一下子很多行) – 我们现在让老师1 后面跟学生(减少重复每次都要出现老师1)

具体操作

1. teacher实体类(放的就是list集合)

1
2
3
private int id;
private String name;
private List<Student> list; //list集合返回结果

2. 只在teacher配置文件改

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
<mapper namespace="com.bjsxt.mapper.TeacherMapper">
<resultMap type="teacher" id="mymap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="list" select="com.bjsxt.mapper.StudentMapper.selByTid" column="id"></collection>
</resultMap>

<select id="selAll" resultMap="mymap">
select * from teacher
</select>

<resultMap type="teacher" id="mymap1">
<id column="tid" property="id"/>
<result column="tname" property="name"/>
<collection property="list" ofType="student" >
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="age" property="age"/>
<result column="tid" property="tid"/>
</collection>
</resultMap>

<select id="selAll1" resultMap="mymap1">
select t.id tid,t.name tname,s.id sid,s.name sname,age,tid from teacher t LEFT JOIN student s on t.id=s.tid;
</select>

</mapper>

结果分析

图例分析流程:

具体实现过程:

1. 准备老师类(要有list集合返回学生类信息)和学生类
2. 准备学生的配置文件(只需要sql语句通过id查所有信息)
3. 准备老师的配置文件
    3.1 通过查询的sql语句去找resultMap标签 然后标签去找学生配置文件的方法查处结果(将id传过去当tid用)
    3.2 因为他返回的结果我需要一个老师对应很多学生 -- 所以我们要再写一个resultMap标签去映射list(一行一行给) --最终通过这个标签返回答案

AutoMapping加载单个对象 ( 添加反单引号 )

使用多表联合查询(起别名!!)

具体操作

1. 学生实体类(老师类对象)

1
2
3
4
5
6
 //只列举了变量
private int id;
private String name;
private int age;
private int tid;
private Teacher teacher; //老师类的对象!!!!!!

2. teacher配置文件(一个是student)

1
2
3
4
5
6
<mapper namespace="com.bjsxt.mapper.TeacherMapper">
<select id="selAll" resultType="teacher">
select t.id id,t.name name,s.id `list.id`,s.name `list.name`,age `list.age`,tid `list.tid`
from teacher t LEFT JOIN student s on t.id=s.tid //展示的是list集合输出
</select>
</mapper>

3. student配置文件(里面通过老师对象(反单引号) teacher.id等传过来用)

1
2
3
4
5
6
7

<mapper namespace="com.bjsxt.mapper.StudentMapper">
<select id="selAll" resultType="student">
select t.id `teacher.id`,t.name `teacher.name`,s.id id,s.name name,age,tid
from student s LEFT JOIN teacher t on t.id=s.tid //里面通过老师对象(反单引号) teacher.id等传过来用)
</select>
</mapper>

Mybatis缓存

缓存概述

提升运行效率(让应用程序减少对数据库的访问)


默认SqlSession缓存开启

1
2
3
4
5
1. 一旦你创建select标签 就会有一个对应statement对象

2. 同一个SqlSession对象调用同一个select --> 只有第一次访问数据库(后面都是将查询结果缓存到SqlSession缓存区)

3. 有效范围: 必须是同一个SqlSession对象(多个sqlsession对象就会执行多次!!)

SqlSessionFactory 二级缓存

引入原因

//问题概述:
    以前要是写两个sql语句两个sqlsession对象 --就会有两个缓存区域 --然后执行就会有两次执行(效率低)

//使用二次缓存:
    让两个sqlsession是获取同一个factory --就只有一个大的单独的缓存区域 -- 就只有一次执行

使用注意事项

1. 有效范围: 
     就是同一个factory的所有SqlSession都可以获取

2. 使用范围
     主要用于数据频繁使用但是很少修改

3. 使用步骤
     只需要在mapper.xml的select标签中添加
            <cache readOnly="true"></cache>

4. 当SqlSession对象进行close() / commit()  --> sqlsession缓存的数据刷  --> SqlSessionFactory缓存区

缓存流程


ThreadLocal

ThreadLocal

线程容器,给线程绑定一个Object内容,只要线程不变就可以随时取出

改变线程 –> 无法(×)取出内容

举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Test {
public static void main(String[] args) {
//使用ThreadLocal类
final ThreadLocal<String> threadLocal=new ThreadLocal<>(); //final不让实例化
threadLocal.set("测试");

//创建子线程
new Thread() {
public void run() //匿名内部类
{
String result = threadLocal.get();
System.out.println("结果"+result);
};
}.start();

String result = threadLocal.get();
System.out.println(result);

}
}

优化线程


动态SQL

动态SQL

根据不同的条件执行不同的SQL语句

Mybatis中动态SQL在mapper.xml里面添加逻辑判断

前期准备:
        1. 准备好之前getMapper接口绑定和参数传递的环境

if

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

//接口需要写方法
List<Log> selByAccinAccout(@Param("accout") String accout,@Param("accin") String accin);

//配置xml文件
<select id="selByAccinAccout" resultType="log">
select * from log where 1=1 //if是需要写where1=1

<!-- OGNL表达式 直接写key / 对象的属性 不需要添加任何特定字符号 -->
<if test="accin!=null and accin!=''">
and accin=#{accin}
</if>

<if test="accout!=null and accout!=''">
and accout=#{accout}
</if>
</select>

where (比if在sql少写where 1=1)

先去掉前面的and 然后加where (先去后加)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

//接口需要写方法
List<Log> selByAccinAccout(@Param("accout") String accout,@Param("accin") String accin);

<select id="selByAccinAccout" resultType="log">
select * from log //省去了if情况要写的where 1=1

<where>
<if test="accin!=null and accin!=''">
and accin=#{accin}
</if>

<if test="accout!=null and accout!=''">
and accout=#{accout}
</if>
</where>

</select>

choose when otherwise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

//接口需要写方法
List<Log> selByAccinAccout(@Param("accout") String accout,@Param("accin") String accin);

<select id="selByAccinAccout" resultType="log">
select * from log
<!-- OGNL表达式 直接写key / 对象的属性 不需要添加任何特定字符号 -->

<where>
<choose>
<when test="accin!=null and accin!=''"> //其实相当于将if改成了when
and accin=#{accin}
</when>
<when test="accout!=null and accout!=''">
and accout=#{accout}
</when>
</choose>
</where>

</select>

set 修改sqlset从句

去掉最后一个逗号 如果set里面有内容就会生成set关键字 (先去后加)

1
2
3
4
凑出形式: 
update log
set id=?,accin=?,accout=?, (最后一个逗号会被set删除掉 )
where id=?
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

//接口写方法
int upd(Log log);

//配置xml里面

<update id="upd" parameterType="log">

update log
<set>
id=#{id},
<if test="accin!=null and accin!=''">
accin=#{accin},
</if>

<if test="accout!=null and accout!=''">
accout=#{accout},
</if>
</set>
where id=#{id}

</update>

//测试类使用接口产生getMapper对象 --然后创建log对象 set添加值
LogMapper logMapper = session.getMapper(LogMapper.class);
Log log=new Log();
log.setId(1);
log.setAccIn(accin); //上面输入
log.setAccOut(accout); //上面输入
int index=logMapper.upd(log); //获得结果

//提交
session.commit(); //一定要记得提交!!! 更新呀
session.close();
System.out.println("程序执行结束");

trim 可以去除和添加

trim属性介绍

1
2
3
4
prefix 在前面添加内容(+)
prefixOverrides 去掉前面内容(-)
suffix 在后面添加内容(+)
suffixOverrides 去掉后面内容(-)

模拟其他功能

先删除and 后添加where (模拟where功能)

1
2
3
4
凑出形式: 
select *
from log
where accin=? //先删除and 然后添加where
1
2
3
4
5
6
7

<select id="selByLog" parameterType="log" resultType="log">
select * from log
<trim prefix="where" prefixOverrides="and">
and accin={accin}
</trim>
</select>

先删除逗号 后添加set (模拟set功能)

1
2
3
4
凑出形式: 
update log
set id=?,accin=?,accout=?, (最后一个逗号会被set删除掉 )
where id=?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

<update id="upd" parameterType="log">
update log
<trim prefix="sex" suffixOverrides=,"">
id=#{id},
<if test="accin!=null and accin!=''">
accin=#{accin},
</if>

<if test="accout!=null and accout!=''">
accout=#{accout},
</if>
</trim>
where id={id}
</update>

bind 重新赋值 / 模糊查询

模糊查询
原内容前/后添加内容

1
2
3
4
<select id="selByLog" parameterType="log">
<bind name="accin" value="'%'+accin+'%'">
#{money}
</select>

foreach

循环参数内容 **
**内容前后添加内容

添加分隔符

属性介绍

1. collection 要遍历的集合
2. item 迭代变量 
      #{迭代变量名}获取内容
3. open 循环后左边添加内容
4. close 循环后右边添加内容
5. separator 每层循环时 元素之间的分隔符

在in查询

1
2
3
4
凑出来:
select *
from log
where id in (1,2,3);
1
2
3
4
5
6
<select id="selIn" parameterType="list" resultType="list">
select * from log where id in

<foreach collection="list" item="abc" open="(" close=")" separator=",">
#{abc}
</select>

批量新增 (效率低)

1. 写sql语句批量新增:

1
2
3
4
凑出来:
insert
into log
values (default,1,2,3),(default,12,2,3),(default,1,22,3)

2. openSession()必须指定

1
factory.openSession(ExecutorType.BATCH);  //底层的PreparedStatement.addBatch();

sql + include 多表查询

多表查询 (sql片段复用)

*将mysql这个表然后内容是四个属性 上面select可以直接include调用 *

1
2
3
4
5
6
7
8
<select id="">
select <include refid="mysql"></include> //直接include的refid标签调用mysql表
from log
</select>

<sql id="mysql">
id,accin,accout,money //给mysql这个表添加一个id 内容是四个属性
</sql>

getMapper接口绑定和多参数传递

Mybatisi接口绑定 + 参数传递

mybatis和spring整合使用的方案

实现步骤:

1.创建接口
    要求:
         1.1 接口包名 == mapper.xml的namespace标签 (接口和配置xml文件在同一个包)
         1.2 接口方法名 == mapper.xml的id属性  (接口名和配置xml里面的id名一样)
2.mybatis.xml全局配置文件中:
    mappers标签里面 -- 使用package标签

举例实现

1. 准备数据库
2. 准备jar包
3. 准备全局mybatis.xml文件
4. 准备实体类 Log
5. 准备mapper包 
    5.1 准备接口 LogMapper
    5.2 准备配置xml文件 LogMapper.xml
6. 准备测试类 test

代码结构层次

实体类

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
public class Log {
private int id;
private String accIn;
private String accOut;
private double money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAccIn() {
return accIn;
}
public void setAccIn(String accIn) {
this.accIn = accIn;
}
public String getAccOut() {
return accOut;
}
public void setAccOut(String accOut) {
this.accOut = accOut;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}

@Override
public String toString() {
return "Log [id=" + id + ", accIn=" + accIn + ", accOut=" + accOut + ", money=" + money + "]";
}

}

全局配置文件

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
<?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>

<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>

<typeAliases>
<package name="com.bjsxt.pojo" />
</typeAliases>

<!-- default引用environment的id,当前所使用的环境 -->
<environments default="default">
<!-- 声明可以使用的环境 -->
<environment id="default">
<!-- 使用原生JDBC事务 -->
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
<property name="username" value="root"/>
<property name="password" value="njdxrjgc7777777."/>
</dataSource>
</environment>
</environments>

<mappers>
<package name="com.bjsxt.mapper"/>
</mappers>

</configuration>

LogMapper接口

1
2
3
4
5
public interface LogMapper {
List<Log> selAll(); //方法名是selAll

List<Log> selByAccInAccount(String accin,String accout); //多参数
}

LogMapper.xml配置文件(sql语句)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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">
<mapper namespace="com.bjsxt.mapper.LogMapper">

<select id="selAll" resultType="log"> <!-- 方法名和接口方法一致 resultYType使用别名 -->
select * from log
</select>

<select id=" selByAccInAccount" resultType="log"> <!-- 多参数不写parameterType -->
select * from log where accin=#{0} and accout=#{1}
</select>

</mapper>

测试代码类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Test {
public static void main(String[] args) throws IOException {
//固定三行
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();

// 使用JDK的动态代理设计模式 面向接口的代理设计模式(必须有接口)
LogMapper logMapper = session.getMapper(LogMapper.class); //给接口产生实例化 接口 -- 实例化proxy -- 反射到xml文件
List<Log> list = logMapper.selAll();
for(Log log1:list) {
System.out.println(log1);
}

List<Log> list2 = logMapper.selByAccInAccount("1","7");
for(Log log2:list2) {
System.out.println(log2);
}

session.close();
System.out.println("程序执行结束");

}
}

多参数传递

1
2
3
4
5
6
7
8
9
10
11
12
	1. 配置文件中写sql语句和id  -- (因为id要和接口方法一致) -- 创建接口方法
sql语句中accin 和 accout写法
第一种: #{0} #{1} 调用方法: "1" "7"
第二种: #{param1} #{param2} 调用方法: "1" "7"
第三种(通过map的实现思路) #{accin} #{accout} 调用方法: @param("accin") @param("accout")

2. 然后测试类调用


```

## 总结 ##
1. 其实就是我们把配置文件的id(sql语句实现的方法)和接口一样 然后通过接口去实例化proxy代理,然后代理反射到xml文件内实现。

2. 之所以可以实例化是因为我们使用其中一种动态代理设计模式  面向接口

    LogMapper logMapper = session.getMapper(LogMapper.class);   //方法要接口的类加载器 调用getMapper方法
        List<Log> list = logMapper.selAll();  //实例化对象获得结果

```


Mybatis实现转账

前期准备

数据库准备

在ssm数据库下通过查询建立account表

导入jar包

准备全局配置文件mybatis.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>

<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>

<typeAliases>
<package name="com.bjsxt.pojo"/> <!-- 起别名 方便在配置的xml里面直接返回值就可以只写类名-->
</typeAliases>

<environments default="default">
<environment id="default">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
<property name="username" value="root"/>
<property name="password" value="njdxrjgc7777777."/>
</dataSource>
</environment>
</environments>

<mappers>
<mapper resource="com/bjsxt/mapper/AccountMapper.xml"/> <!-- 直接调用配置文件 执行sql语句 -->
</mappers>

</configuration>

准备pojo包的实体类Account

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

public class Account {
private int id;
private String accNo;
private int password;
private String name;
private double balance;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAccNo() {
return accNo;
}
public void setAccNo(String accNo) {
this.accNo = accNo;
}
public int getPassword() {
return password;
}
public void setPassword(int password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}

准备mapper包下的AccountMapper.xml文件

通过分析我们要有三个任务:分别是写在三个select标签下完成对应任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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">

<mapper namespace="com.bjsxt.mapper.AccountMapper">
<!-- 根据帐号和密码查询账户信息 -->
<select id="selByAccnoPwd" resultType="account" parameterType="account"> //id就是此方法名称 resultType就是返回值类型
select * from account where accno=#{accNo} and password=#{password}
</select>

<!-- 根据帐号和姓名查询账户信息 -->
<select id="selByAccnoName" resultType="account" parameterType="account">
select * from account where accno=#{accNo} and name=#{name}
</select>

<!-- 根据accNo修改账户余额 -->
<update id="updBalanceByAccno" parameterType="account">
update account set balance=balance+#{balance} where accno=#{accNo}
</update>

</mapper>

准备serive包下的AccountService接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface AccountService {

//帐号和密码不匹配状态码
int ACCOUNT_PASSWORD_NOT_MATCH=1;

//余额不足
int ACCOUNT_BALANCE_NOT_ENOUGH=2;
//账户姓名不匹配
int ACCOUNT_NAME_NOT_MATCH=3;
//转账失败
int ERROR=4;
//转账成功
int SUCCESS=5;

//转账功能
int transfer(Account accIn,Account accOut) throws IOException;

}

准备1.0版本的serviceimpl包

准备思路:

1. 先判断账号和密码是否匹配 (调用方法查sql语句)
    2. 然后判断是否有足够转账金额 (判断账号密码查信息返回给account类 然后调用balance去判断是否足够)
        3. 判断收款人账号和名字是否正确 
            4. 然后进行转账交易 (调用方法 一个减少一个增加)
                5. 判断是不是成功
                    5.1 成功就session.commit()提交 --  session.close()关闭  -- 返回成功的结果值
                    5.2 失败就session.rollback()回滚 --session.close()关闭 -- 返回失败的结果值 

实现类实现初级1.0事务:

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

public class AccountServiceImpl implements AccountService {
@Override
public int transfer(Account accIn, Account accOut) throws IOException {

//固定的三行生产出session
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();

//先判断帐号和密码是否匹配
Account accOutSelect = session.selectOne("com.bjsxt.mapper.AccountMapper.selByAccnoPwd",accOut); //根据账号和密码查询
if(accOutSelect!=null){ //账号和密码匹配
if(accOutSelect.getBalance()>=accOut.getBalance()) { //余额够
Account accInSelect = session.selectOne("com.bjsxt.mapper.AccountMapper.selByAccnoName",accIn); //根据账号和姓名查询
if(accInSelect!=null) {
accOut.setBalance(-accOut.getBalance()); //set设置一下为负数
int index=session.update("com.bjsxt.mapper.AccountMapper.updBalanceByAccno",accOut); //如果传的是accOut 就需要的是扣除交易额
index += session.update("com.bjsxt.mapper.AccountMapper.updBalanceByAccno",accIn); //转账过去
if(index==2) {
session.commit(); //成功就提交
session.close();
return SUCCESS;
}else {
session.rollback(); //失败就要回滚
session.close();
return ERROR;
}
}else {
return ACCOUNT_NAME_NOT_MATCH; //账号和姓名不匹配
}
}else {
return ACCOUNT_BALANCE_NOT_ENOUGH; //余额不足
}
}else{
return ACCOUNT_PASSWORD_NOT_MATCH; // 账号和密码 不匹配
}

}
}

准备servlet包下的TransferServlet类

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

@WebServlet("/transfer")
public class TransferServlet extends HttpServlet {

//面向接口编程
private AccountService accService = new AccountServiceImpl();

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//需要使用到中文
req.setCharacterEncoding("utf-8");

//获取转账人的信息
Account accOut = new Account();
accOut.setAccNo(req.getParameter("accOutAccNo"));
accOut.setPassword(Integer.parseInt(req.getParameter("accOutPassword")));
accOut.setBalance(Double.parseDouble(req.getParameter("accOutBalance")));

//获取收款人信息
Account accIn =new Account();
accIn.setAccNo(req.getParameter("accInAccNo"));
accIn.setName(req.getParameter("accInName"));

//通过面向接口编程 调用转账功能
int index = accService.transfer(accIn, accOut);

if(index==AccountService.SUCCESS) //转账成功的返回值和 service的静态success对比
{
resp.sendRedirect("/bank/show"); //成功跳转到展示页面
}
else
{
HttpSession session = req.getSession();
session.setAttribute("code", index); // 获得状态码
resp.sendRedirect("/bank/error/error.jsp"); //新建的error文件下的error.jsp页面
}

}
}

准备登陆/失败/转账查询的页面

log显示成功界面

1
2
3
<body>
成功的log.jsp
</body>

index主页面界面

1
2
3
4
5
6
7
8
9
10
11
12
<body>

<form action="transfer" method="post"> //写一个页表 -- servlet类
转账账户:<input type="text" name="accOutAccNo"/><br/>
密码:<input type="password" name="accOutPassword"/><br/>
金额:<input type="text" name="accOutBalance"/><br/>
收款帐号:<input type="text" name="accInAccNo"/><br/>
收款姓名:<input type="text" name="accInName"/><br/>
<input type="submit" value="转账"/>
</form>

</body>

error错误界面

1
2
3
4
5
<body>
对不起操作失败:<br/>
错误原因:
${sessionScope.code} //通过jsp方式传出错误的原因对应的service的数字
</body>

准备log4j (查错)

带入jar包和配置文件log4j.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
log4j.rootCategory=ERROR, CONSOLE ,LOGFILE   //显示设置error去查找错误

log4j.logger.com.bjsxt.mapper=DEBUG //给这个包添加log4j文件

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%C %d{YYYY-MM-dd hh:mm:ss} %m %n

log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=E:/my.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%m %n

全局配置文件中配置log4j

1
2
3
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>

执行结果


日志记录

创建表log

1
2
3
4
5
6
create table log(
id int(10) primary key auto_increment,
accout varchar(18),
accin varchar(8),
money double
);

新增log实体类

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
public class Log {
private int id;
private String accIn;
private String accOut;
private double money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAccIn() {
return accIn;
}
public void setAccIn(String accIn) {
this.accIn = accIn;
}
public String getAccOut() {
return accOut;
}
public void setAccOut(String accOut) {
this.accOut = accOut;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}

新增关于log表的配置xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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">
<mapper namespace="com.bjsxt.mapper.LogMapper">

<insert id="insLog" parameterType="log">
insert into log values(default,#{accOut},#{accIn},#{money}) //添加数据
</insert>

<select id="selByPage" parameterType="map" resultType="log"> //分页
select * from log limit #{pageStart},#{pageSize}
</select>

<select id="selCount" resultType="long"> //查询所有
select count(*) from log
</select>

</mapper>

在serviceimpl实现类添加

1
2
3
4
5
6
7
8

//在已经转账成功 index==2之后添加

Log log=new Log();
log.setAccIn(accIn.getAccNo()); //取出来所有信息然后添加到log实体类对象
log.setAccOut(accOut.getAccNo());
log.setMoney(accIn.getBalance());
session.insert("com.bjsxt.mapper.LogMapper.insLog",log); //转账成功就添加到log表里面

日志文件显示转账信息(log4j)

1
2
3
4
5
6
//1. 要在log4j配置文件内更改:
log4j.appender.LOGFILE.layout.ConversionPattern=%m %n //最后要是%m %n

//2. 在刚才的实现类代码下添加日志文件记录(同时将log4j第一行的异常给一个info才可以显示)
Logger logger=Logger.getLogger(AccountServiceImpl.class);
logger.info(log.getAccOut()+"给"+log.getAccOut()+"在"+new Date().toLocaleString()+"转了"+log.getMoney()); //在log4j的五种异常中选info异常

分页展示功能

mapper包xml里面添加分页功能的sql语句

1
2
3
4
5
6
7
<select id="selByPage" parameterType="map" resultType="log">  //分页
select * from log limit #{pageStart},#{pageSize}
</select>

<select id="selCount" resultType="long"> //查询所有
select count(*) from log
</select>

添加分页显示的实体类

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
public class PageInfo {
private int pageSize;
private int pageNumber;
private long total;
private List<?> list;
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public List<?> getList() {
return list;
}
public void setList(List<?> list) {
this.list = list;
}

}

service层接口实现方法

1
2
3
4
5
6
7
8
9
public interface LogService  {
/**
* 分页显示
* @param pageSize
* @param pageNumber
* @return
*/
PageInfo showPage(int pageSize,int pageNumber) throws IOException;
}

service实现类

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

public class LogServiceImpl implements LogService {

@Override
public PageInfo showPage(int pageSize, int pageNumber) throws IOException {

//固定三行
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();

Map<String,Object> param = new HashMap<>();
param.put("pageStart",pageSize*(pageNumber-1)); //获取当前页要从第几个开始
param.put("pageSize", pageSize); //获取一页展示几个


List<Log> list = session.selectList("com.bjsxt.mapper.LogMapper.selByPage",param); //param是一个map 创建一个map 将最后的map集合的值给log实体类
long count = session.selectOne("com.bjsxt.mapper.LogMapper.selCount"); //查询总数

PageInfo pi = new PageInfo(); //分页类实现对象(四个属性)
pi.setList(list);
pi.setPageNumber(pageNumber);
pi.setPageSize(pageSize);
pi.setTotal(count%pageSize==0?count/pageSize:count/pageSize+1); //算出来总共几个几页

return pi;

}
}

准备servlet类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

@WebServlet("/show")
public class ShowServlet extends HttpServlet {
private LogService logService = new LogServiceImpl();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

int pageSize = 2;
String pageSizeStr = req.getParameter("pageSize"); //获取一页有几个
if(pageSizeStr!=null&&!pageSizeStr.equals("")){
pageSize = Integer.parseInt(pageSizeStr); //强转
}
int pageNumber = 1;
String pageNumberStr = req.getParameter("pageNumber"); //获取有几页
if(pageNumberStr!=null&&!pageNumberStr.equals("")){
pageNumber = Integer.parseInt(pageNumberStr); //强转
}

//最后跳转
req.setAttribute("pageinfo", logService.showPage(pageSize, pageNumber));
req.getRequestDispatcher("/log.jsp").forward(req, resp); //跳转

}
}

书写log.jsp页面

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
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<table border="1">
<tr>
<th>转账帐号</th>
<th>收款帐号</th>
<th>转账金额</th>
</tr>
<c:forEach items="${pageinfo.list}" var="log">
<tr>
<td>${log.accOut }</td>
<td>${log.accIn }</td>
<td>${log.money }</td>
</tr>
</c:forEach>
</table>
<a href="show?pageSize=${pageinfo.pageSize }&pageNumber=${pageinfo.pageNumber-1}" <c:if test="${pageinfo.pageNumber<=1 }"> onclick="javascript:return false;"</c:if>>上一页</a>
<a href="show?pageSize=${pageinfo.pageSize }&pageNumber=${pageinfo.pageNumber+1}" <c:if test="${pageinfo.pageNumber>=pageinfo.total }"> onclick="javascript:return false;"</c:if>>下一页</a>
</body>
</html>

全局配置文件添加mappers

1
2
3
4
<mappers>
<mapper resource="com/bjsxt/mapper/AccountMapper.xml"/> <!-- 直接调用配置文件 执行sql语句 -->
<mapper resource="com/bjsxt/mapper/LogMapper.xml"/> <!-- 直接调用配置文件 执行sql语句 -->
</mappers>

总结

最终代码结构:

最终结果:


Mybatis实现分页功能(完整流程)

Mybatis实现分页功能

准备数据库

实体类 People

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
public class People {
private int id;
private String name;
private int age;
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}

导入相关jar包

全局配置文件mybatis.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
<?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"> <!--dtd文件 约束(chm文件可以找到)-->

<configuration>

<typeAliases>
<package name="com.bjsxt.pojo"/> <!-- 起别名 方便在配置的xml里面直接返回值就可以只写类名-->
</typeAliases>

<environments default="default">
<environment id="default">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
<property name="username" value="root"/>
<property name="password" value="njdxrjgc7777777."/>
</dataSource>
</environment>
</environments>

<mappers>
<mapper resource="com/bjsxt/mapper/PeopleMapper.xml"/> <!-- 直接调用配置文件 执行sql语句 -->
</mappers>

</configuration>

配置PeopleMapper.xml

1
2
3
4
5
6
7
8
9
10
11
<?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"> <!--dtd文件 约束(chm文件可以找到)-->

<mapper namespace="com.bjsxt.mapper.PeopleMapper" > <!-- 确定这个mapper名字: 包.类名 -->
<select id="selByPage" resultType="People" parameterType="map"> <!-- 确定方法叫selByPage 返回值给people实体类 传入参数的类型是map -->
select * from people limit #{pageStart},#{pageSize}; <!-- limit 后面通过#{}方式传入两个map参数-->
</select>
</mapper>

构建实体类pageInfo用于传递分层相关的参数

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

public class PageInfo {

private int pageSize; //一页分布几个
private int pageNumber; //第几页
private long total; //一共总页数 分多少页
private List<?> list; //当前页显示哪些数据

public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public List<?> getList() {
return list;
}
public void setList(List<?> list) {
this.list = list;
}

}

service和实现层

service层实现代码:

1
2
3
4
public interface PeopleService {
//实现分页展示 传入两个参数
PageInfo showPage(int pageSize,int pageNumber) throws IOException;
}

serviceimpl层实现代码:

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
public class PeopleServiceImpl implements PeopleService {

@Override
public PageInfo showPage(int pageSize, int pageNumber) throws IOException {

//获取配置资源
InputStream is = Resources.getResourceAsStream("mybatis.xml");

//使用构建者模式(加快工厂实例化)和工厂模式生产session
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();

//创建对象
PageInfo pi=new PageInfo();
pi.setPageNumber(pageNumber);
pi.setPageSize(pageSize);

//新建map对象
Map<String,Object> map=new HashMap<>();
map.put("pageStart",pageSize*(pageNumber-1)); //设置好每一页开始的那个数字
map.put("pageSize",pageSize); //设置好每一页有几个
pi.setList(session.selectList("com.bjsxt.mapper.PeopleMapper.selByPage",map)); //要设置返回结果 第二个参数是传入两个key值

//总条数
long count=session.selectOne("com.bjsxt.mapper.PeopleMapper.selCount"); //获取查询总条数

pi.setTotal(count%pageSize==0?count/pageSize:count/pageSize+1); //要设置总共几页 总数/每一页

return pi;
}

}

因为要获得所有数count 要在xml配一个查询所有的select标签

1
2
3
<select id="selCount" resultType="Long">
select count(*) from people
</select>

Servlet类

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
@WebServlet("/page")  //使用注解的方式 最后要在web里面写/page才可以

public class ShowPageServlet extends HttpServlet{

//面向接口编程
private PeopleService peopleService=new com.bjsxt.serviceimpl.PeopleServiceImpl();

@Override
protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{

//第一次访问的验证 如果没有传递参数 设置默认值
String pageSizeStr = req.getParameter("pageSize");
int pageSize=2; //一页显示几个
if(pageSizeStr!=null&&!pageSizeStr.equals(""))
{
pageSize = Integer.parseInt(pageSizeStr); //获取两个参数
}

String pageNumberStr = req.getParameter("pageNumber");
int pageNumber = 1; //显示第几页
if(pageNumberStr!=null&&!pageNumberStr.equals(""))
{
pageNumber = Integer.parseInt(pageNumberStr); //获取两个参数
}

PageInfo pi=peopleService.showPage(pageSize, pageNumber); //分页展示效果给了pageinfo实体类

// 传过去
req.setAttribute("PageInfo", pi);

// 请求转发
req.getRequestDispatcher("index.jsp").forward(req, resp);

}

}

index.jsp页面

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
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<table border="1">
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
</tr>
<c:forEach items="${PageInfo.list }" var="pi">
<tr>
<td>${pi.id }</td>
<td>${pi.name }</td>
<td>${pi.age }</td>
</tr>
</c:forEach>
</table>

<!-- 跳转通过onclick点击事件 然后js的行内表达方式 取消跳转等功能 c:if进行判断 -->
<a href="page?pageNumber=${PageInfo.pageNumber-1 }&pageSize=${PageInfo.pageSize}" <c:if test="${PageInfo.pageNumber<=1 }"> onclick="javascript:return false;" </c:if> >上一页</a>
<a href="page?pageNumber=${PageInfo.pageNumber+1 }&pageSize=${PageInfo.pageSize}" <c:if test="${PageInfo.pageNumber>=PageInfo.total }"> onclick="javascript:return false;" </c:if> >下一页</a>

</body>
</html>

结果和分析

一定要在输入的后面添加注解的 /path :

完整代码放在mybatis分页的仓库里面


Mybatis实现新增删除修改和事务讲解

前期知识

项目分工

功能:从应用程序角度出发,软件具有哪些功能
业务:完成功能需要的逻辑 – 对应service中一个方法
事务:从数据库角度出发,完成业务时需执行的sql集合 叫做一个事务

mybatis对于JDBC

mybatis中默认是关闭JDBC的自动提交功能

每一个SqlSession默认是不自动提交事务
    1. session.commit() 提交事务
    2. openSession(true) 自动提交 [setAutoCommit(true)]

mybatis底层是对JDBC的封装

1. JDBC中executeUpdate()  执行增加/删除/修改
     返回值都是int
2. mybatis中insert/delete/update标签   执行增加/删除/修改
    没有resultType属性  认为返回值是int

在openSession()时,Mybatis会创建SqlSession+ 创建一个Transaction(事务对象) + autoCommit属性都是false

回滚(用try catch抓) session.rollback()回顾事务


Mybatis实现新增

mapper.xml中提供insert标签

1
2
3
<insert id="tianjia" parameterType="People">       //id是表示现在的方法叫tianjia  然后没有返回值  使用别名People直接用(对整个包取别名)
insert into people values(default,#{name},#{age}) //sql语句 要传进来name 和 age 两个属性
</insert>

test类session提供insert方法

1
2
3
4
5
6
7
8
9
10
11
12
13
 People p=new People();
p.setName("新增name1");
p.setAge(88);

int index1=session.insert("a.b.tianjia",p); //判断是否成功 默认返回值是int类型
if(index1>0)
{
System.out.println("成功");
}
else
{
System.out.println("失败");
}

Mybatis实现mysql分页

Xml文件转义标签

Xml出现一些特殊字符(< > “”)就是用Xml自带的文件转义标签

1
<![CDATA[内容]]>

mysql语句分页演示


mybaitis中实现mysql分页写法

  • *1. ? 不允许(×)出现在关键字前后进行数字运算 (因为原来查出来log4j返回出来sql语句是 id=?的形式) *

  • 2. java中解决(?)方法 – (直接在传之前我就让?的值被计算好)

test类:

1
2
3
4
5
6
7
8
9
10
11
12
13
//显示几个
intpageSize=2;

//第几页
intpageNumber=2;

//如果希望传递多个参数,可以使用对象或map

Map<String,Object>map=newHashMap<>(); //定义一个map集合: 第一个key是字符串 第二个key是object
map.put("pageSize",pageSize); //算好 一页显示几个
map.put("pageStart",pageSize*(pageNumber-1)); //算好 第几页从第几个下标开始

List<People>p=session.selectList("com.bjsxt.pojo.mapper.page",map); //找包下面类的page方法 查出来的结果给list集合

** 在mapper.xml配置文件:**

1
2
3
<select id="page" resultType="com.bjsxt.pojo.People"  parameterType="map">  //传入的参数类型是map
select * from people limit #{pageStart},#{pageSize} //传入两个值
</select>

别名(typeAliases标签)

每一次用sql语句就要写一次select标签的属性然后返回结果list集合给实体类
所以引入了别名的机制更加方便

系统内置别名

1
把类型全小写即可

给某个类(typeAlias标签) 方便一个表的多个方法使用

1.直接在全局配置文件内加typeAliases标签

1
2
3
4
5
//在全局配置文件的<configuration>标签内加:

<typeAliases>
<typeAlias type="com.bjstx.pojo.People" alias="peo"/> //意思就是将type里面的内容取个别名叫做peo
</typeAliases>

2.之后就可以在mapper.xml配置文件的select标签的resultType内容改为别名peo

1
2
3
<select id="page" resultType="peo"  parameterType="map">  //传入的参数类型是map  返回给peo(别名)
select * from people limit #{pageStart},#{pageSize} //传入两个值
</select>

给某个包所有类(package标签) 方便多个表进行操作

1.直接在全局配置文件内加typeAliases标签

1
2
3
4
5
//在全局配置文件的<configuration>标签内加:

<typeAliases>
<package name="com.bjsxt.pojo"/> //这个包下肯定有很多操作数据库的配置文件
</typeAliases>

2.之后就可以在mapper.xml配置文件的select标签的resultType内容直接使用实体类的类名

1
2
3
<select id="page" resultType="People"  parameterType="map">  //传入的参数类型是map  返回值就直接写配置别名的类的类名
select * from people limit #{pageStart},#{pageSize} //传入两个值
</select>

Mybatis查询所有

前期准备

准备数据库

最终结果:

sql语句:

1
2
3
4
5
6
7
8
create table people(
id int(10) primary key auto_increment comment '编号',
name varchar(20) comment '姓名',
age int(3) comment '年龄'
)comment '人员信息表';

insert into people values(default,'张三',21);
insert into people values(default,'李四',22);

准备实体类People

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

public class People {

private int id; //和数据库的属性匹配
private String name;
private int age;

public int getId() { //生成所有的set和get方法
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

搭建环境

  • *1. 导入mybatis的jar包 + 依赖包 + mysql的jar包 + jstl的jar包 *

  • 2. 搭建全局配置文件

    1. 中文chm文档dtd文件找约束
    2. 写configuration内容 -- 配置数据库
    3. 写mappers的配置 -- 找PeopleMapper.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
<?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>
<environments default="default">
<environment id="default">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
<property name="username" value="root"/>
<property name="password" value="njdxrjgc7777777."/>
</dataSource>
</environment>
</environments>

<!--第三步-->
<mappers>
<mapper resource="com/bjstx/mapper/PeopleMapper.xml"/>
</mappers>

</configuration>
  • 3. 搭建类似于实现类的xml文件

    1. 中文chm文档dtd文件找约束
    2. 写mapper配置 -- 里面写sq语句和返回值和方法名等信息
1
2
3
4
5
6
7
8
9
10
11
12
13
<?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">

<!-- 第二步 -->
<mapper namespace="com.bjsxt.mapper.PeopleMapper" >
<select id="selAll" resultType="com.bjsxt.pojo.People">
select * from people
</select>
</mapper>

准备service层和实现层

PeopleService接口写方法

1
2
3
4
5
public interface PeopleService {

//显示人员
List<People> show() throws IOException;
}

PeopleServiceImpl类实现PeopleService接口

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
/*
* 数据访问层 -- 处理异常和控制器中处理异常 service只是抛出异常
*/
public class PeopleServiceImpl implements PeopleService{

@Override
public List<People> show() throws IOException {
// 1. 找主配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");

// 2. 使用工厂模式 实例化工厂对象使用构建者模式 (名称标志后面:Builder)
//构建者设计模式意义:简化对象实例化过程 (我们这个SqlSessionFactory里面还要很多类很多方法比较麻烦)
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);

// 3. 创建session
SqlSession session=factory.openSession();

//4. 调用xml配置文件中的功能
List<People> list = session.selectList("com.bjsxt.mapper.PeopleMapper.setAll");

//5. 关闭连接
session.close();

return list;
}

}

准备Servlet层

1
2
3
4
5
6
7
8
9
10
11
12
13
@WebServlet("/abc/b/show")  //1.是给默认属性赋值 省略 value=  2.数组是一个值 省略 {}
public class ShowServlet extends HttpServlet {
//面向接口编程
private PeopleService peopleService=new PeopleServiceImpl();

@Override
protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
List<People> list = peopleService.show();
req.setAttribute("list", list);
//使用请求转发 这次是相对路径
req.getRequestDispatcher("/index.jsp").forward(req, resp); // "/" 全路径(对WebContent目录) "" 相对路径
}
}

index.jsp首页

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
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<table>
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
</tr>
<c:forEach items="${list }" var="peo">
<tr>
<td>${peo.id}</td>
<td>${peo.name}</td>
<td>${peo.age}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
,