Fork me on GitHub

mybatis实现复杂查询

mybatis实现复杂查询

实现复杂查询的环境配置

我们需要准备的东西:

  • 两个带有相联结的数据库表格(以student和teacher为例)
  • 创建一个带有日志的使用lambok插件的优化配置后的java项目

两个数据库表格的准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, 秦老师);

CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO `student` (`id`, `name`, `tid`) VALUES (1, 小明, 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (2, 小红, 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (3, 小张, 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (4, 小李, 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (5, 小王, 1);

在执行sql时注意:不能直接执行玩全部的sql,因为可能在执行插入操作前,还没有将表格建好。

java项目的准备

  • 导入lambok包(直接放到父项目的xml中,这样每个子项目都能直接使用了)

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
    </dependency>
  • 设置日志(在子项目的核心配置文件中设置最简单的日志)

    1
    2
    3
    4
    <!--这里设置了一个最基础的日志-->
    <settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
  • 编写剩余的java程序(pojo,until等)

需要注意的点在于:

  • 这一次我么使用了两个实体类,因此为了体现分离的原则,我们把Mapper.xml创建到resource文件夹下,但是要求1.mapper.xml也有相同的包结构 2.mapper.xml与其对应的抽象类同名

    文件位置关系

  • 创建好的每一个xml都需要在核心配置文件中进行配置

    1
    2
    3
    4
    <mappers>
    <mapper resource="com/dwx/mapper/TeacherMapper.xml"/>
    <mapper resource="com/dwx/mapper/StudentMapper.xml"/>
    </mappers>

解释上述为何要相同的包结构:因为在生成target文件时,由于两者有相同的包结构 就会被当成是在一个包下,这就符合了我们之前要求的xml文件与接口类在同一包下且同名的要求

target文件结构

处理多对一问题

处理多对一问题即:从多个表中查寻相关联的数据。

处理方法在MySQL中有两种:

  • 子查询
  • 联表查询

因此在java程序中也出现两种方法:

  • 按照查询嵌套处理
  • 按照结果嵌套处理

按照查询嵌套处理

按照查询嵌套处理的逻辑等同于mysql中的子查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--第一种使用子查询 基本原理 在查询到tid后再查询tname-->

<select id="getStudent_Teacher" resultMap="studentTeacherMap">
select * from mybatis.student1
</select>
<resultMap id="studentTeacherMap" type="Student">
<!--对于基本属性直接进行映射即可-->
<result property="id" column="id"/>
<result property="name" column="id"/>
<!--但是对于引用参数 需要使用assocation来操作-->
<!--这里是嵌套一个方法-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from mybatis.teacher where id = #{tid}
</select>

注意点:

  • 对于<resultmap>,如果是基本类型,直接使用映射即可
  • 如果是引用类型使用<association>
  • 如果是集合类型则使用<collection>

原理就是在每一次查询到tid时到teacher表中查询teacher的名字

用SQL表现为:

1
2
SELECT student1.`id`,student1.`name` ,(SELECT teacher.`name` WHERE teacher.`id` = student1.`tid`) AS teachername
FROM student1,teacher

按照结果嵌套处理

使用这种方法进行处理相当于sql中的联表查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--使用联表查询-->
<select id="getStudent_Teacher2" resultMap="studentTeachermap">
<!--下边是使用链表查询的sql-->
select s.id sid,s.name sname,t.name tname
from student1 s,teacher t
where s.tid = t.id
</select>
<!--西边是链表查询的resultmap-->
<resultMap id="studentTeachermap" type="Student">
<result column="sid" property="id"/>
<result column="sname" property="name"/>
<association property="teacher" javaType="Teacher">
<result column="tname" property="name"/>
</association>
</resultMap>

注意:

  • 这里我们使用了大量的别名 因此在映射时,数据库一边的参数用别名表示
1
2
3
SELECT s.id sid,s.name sname,t.name tname
FROM student1 s,teacher t
WHERE s.tid = t.id

处理一对多问题

环境准备:一对多,一个老师对应多个学生,因此老师的参数有一个是一个一student为类型的集合

而学生参数变为和数据库中参数一样。

student类

1
2
3
4
5
6
7
8
9
10
11
//编写Student实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private int id;
private String name;
//这里是一个联表 在java代码中 直接把链表的参数放进去
private int tid;
}

teacher类

1
2
3
4
5
6
7
8
9
10
//编写Teacher的实体类
//这里直接使用注解来完成实体类的完善
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private String name;
private int id;
private List<Student> studentList;
}

注意:此时由于teacher类中使用了List<Student>因此在SQLresultmap中有所改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<mapper namespace="com.dwx.mapper.TeacherMapper">
<select id="getTeacher" resultMap="teacherMap">
select s.id sid,s.name sname,t.name tname,t.id tid
from mybatis.teacher t, mybatis.student1 s
where s.tid = t.id
</select>
<resultMap id="teacherMap" type="Teacher">
<result property="id" column="id"/>
<result property="name" column="name"/>
<collection property="studentList" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="stid"/>
</collection>
</resultMap>
</mapper>

注意:使用<collection property="java中的属性" foType="list的类型"></collection>这样来给List集合做映射。

Lombok插件的使用

Lombok插件的使用

Lombok插件能够方便pojo类的编写(实体类的编写)

使用Lombok插件的使用可以代替(get/set方法、构造器、toString、hashcode等的编写)

Lombok插件的安装

安装步骤:

  1. 在IDEA中安装Lombok插件:(Setting->plugins->insert…)

    插件安装位置

  2. 导入Lombok的Jar包(project Lombok)[删除<scope></scope>]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <dependencies>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
    </dependency>

    </dependencies>
  3. 使用Lombok

使用Lombok

在以前 我们都是使用Alt+Ins来方便编写get\set方法等等

以前的实体类

但现在 我们仅仅使用@注解就能完成这个工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.dwx.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

//创建与数据库映射的类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class student {
private int id;
private String name;
private String password;

}

现在的编写方法

注解的解释:

  • @Data:代替get/set方法、无参构造、toString、hashcode、equals
  • @AllArgsConstructor:代替有钱构造
  • @NoArgsConstructor:代替无参构造

这个插件还有很多的注解 但是最重要的只有以上三个

mybatis使用注解开发

mybatis使用注解开发

在对接口就行实现时,我们既可以使用xml文件进行配置,也可以使用注解也进行配置。

使用注解进行配置,操作简单,但是功能也简单,复杂的操作还得使用xml配置来实现

使用注解实现查询

使用注解实现查询的底层逻辑是反射

使用注解进行查询与使用xml进行配置除了没有实现的mapper.xml文件外其他的都一致

**文件结构: **

文件结构

少了StudentMapper,xml文件

接口代码

1
2
3
4
5
6
7
8
9

public interface StudentMapper {

//测试使用注解来实现查询
@Select("select * from mybatis.student")
List<student> getStudentList();

}

此时的接口直接在抽象方法上使用注解@Select并且在()里编写SQL语句

核心配置文件代码:

1
2
3
<mappers>
<mapper class="com.dwx.mapper.StudentMapper"/>
</mappers>

虽然没有了xml,但是还是需要进行配置,这里使用的参数是class自然对应我们接口类的全路径

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class test {
@Test
public void getStudentList(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<student> studentList = mapper.getStudentList();
for (student student : studentList) {
System.out.println(student.toString());
}
sqlSession.close();
}
}

测试代码和使用xml时一模一样 没有任何改变。

自动提交事务

之前我们使用的方法提交事务的方法是手动提交事务:

until文件中的代码:

1
sqlSessionFactory.openSession();

测试类中的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void InsertStudnet(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
//获得了sqlSession就需要进行联结获得mapper
UserDao mapper = sqlSession.getMapper(UserDao.class);
//通过mapper对象来进行操作
mapper.InsertStudent(new student(4,"王五","123456"));
//对于需要对数据库进行改动的如:“增删改” 都系要提交事务
sqlSession.commit();//此代码就是提交事务
//关闭sqlsession
sqlSession.close();
}

但是现在 我们在开始SQLsession时就直接设置自动提交事务

1
sqlsessionFactory.openSession(true);

此时就不需要sqlsession.commit(),每一条语句都会自动提交 但是如果sql出错还是会提交 会出现错误

使用注解实现有参查询

实现基础:@Param("名字")注解的使用

在参数前使用@Param("名字")这个注解,然后在@Select(“sql”)中使用#{"名字"}来获取参数。

接口代码:

1
2
3
//测试使用注解实现有参查询
@Select("select * from mybatis.student where id = #{id}")
student getStudentByID(@Param("id") int id);

注意:有几个参数就在几个参数前加@Param("名字")

使用注解实现增加

接口代码:

1
2
3
4
//测试使用注解实现增加
@Insert("insert into mybatis.student (id,name,password) values(#{id},#{name},#{password})")
int InsertStudent(student student);

注意:我们这里的参数是student,是我创建的实体类 也就是引用类,引用类是不需要添加@Params("名字")的,直接使用即可。通过#{"参数名"}就直接获取了应用参数内部包含的参数。

而且此时我们已经设置了自动提交事务,就不用在写sqlsession.commit()了。

使用注解实现删除

接口代码:

1
2
3
//测试使用注解实现删除
@Delete("delete from mybatis.student where id = #{id}")
int DeleteStudentById(@Param("id") int id);

使用注解实现修改

接口代码:

1
2
3
//测试使用注解实现修改
@Update("Update mybatis.student set name = #{name},password = #{password} where id = #{id}")
int UpdateStudentById(@Param("id") int id,@Param("name") String name,@Param("password") String password);

注意:修改sql的书写,有几个参数就在几个参数前加@Param("名字")

@Param("名字")使用的注意事项

  • 有几个参数就在几个参数前加@Param("名字")
  • 基本数据类型以及String加注解,自己创造的实体类(引用数据类型)不用加注解

mybatis实现分页

mybatis实现分页

分页的意义:分页的意义在于减少了数据的处理量

分页可以通过一下的方式实现:

  • sql中的limit实现分页
  • 在java代码中使用RowBounds实现分页

limit实现分页

核心SQL语法:

1
SELECT * FROM 表格名 limit startIndex,pageSize

元素分析:

  • startIndex: 指的是重哪个数据开始查询(默认是从0开始的)
  • pagesize: 指纸张的大小,可以查询到几个元素

回顾mybatis实现一个操作需要的步奏:

  • 编写接口
  • 编写Mapper.xml(主要写sql)
  • 编写测试方法

接口代码:

1
List<student> getStudentListByLimit(Map<String,Object> map);

这里使用的万能的map作为参数

Mapper.xml代码:

1
2
3
<select id="getStudentListByLimit" resultMap="StudentMap" parameterType="map">
select * from mybatis.student limit #{startIndex},#{pageSize}
</select>

有参数的查询必须要规定参数的类型

这里使用的resultMap(结果集映射)作为返回

实现方法代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void getStudentListByLimitTest(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("startIndex",1);
map.put("pageSize",2);
List<student> studentListByLimit = mapper.getStudentListByLimit(map);
for (student student : studentListByLimit) {
System.out.println(student.toString());
}
sqlSession.close();
}

固定格式

RowBounds实现分页

这是更加服了java面向对象特点的方法,没有在sql进行操作,在测试类中进行操作

这种方法已经过时

操作步奏:

  • 接口

    1
    List<student> getStudentByRowBounds();
  • Mapper.xml

    1
    2
    3
    <select id="getStudentByRowBounds" resultMap="StudentMap">
    select * from mybatis.student
    </select>
  • 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @Test
    public void getStudentByRowBounds(){
    MyBatisUtils myBatisUtils = new MyBatisUtils();
    SqlSession sqlSession = myBatisUtils.getSqlSession();
    //其特点就是在sqlsession中直接进行select
    //第三个参数是RowBounds 因此需要创建
    //第一个参数是起始数,第二个参数是页面大小
    RowBounds rowBounds = new RowBounds(0, 3);
    List<student> students = sqlSession.selectList("com.dwx.mapper.StudentMapper.getStudentByRowBounds", null, rowBounds);
    for (student student : students) {
    System.out.println(student.toString());
    }
    }

selectList()方法有三个参数

第一个参数是我们执行这个方法的全路径,第二个数据一般是null,第三个数据是rowBounds

注意:我们这里并没有使用mapper,而是使用selectList,这种方法是已经放弃了的

mybatis日志工厂

mybatis日志工厂

如果一个数据库操作出现了一个异常,我们需要进行排除。日志就是最好的助手。

在以前,我们在程序拍错时使用的是sout获得debug

现在,我们就能够使用日志来进行排错了

日志_MyBatis中文网

日志我们只需要了解两种:STDOUT_LOGGINGLOG4J

STDOUT_LOGGING的使用

STDOUT_LOGGING 的使用十分方便 只需要在核心配置文件(mybatis-config.xml)中配置settings就行

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

配置完就可以直接进行测试

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
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
Class not found: org.jboss.vfs.VFS
JBoss 6 VFS API is not available in this environment.
Class not found: org.jboss.vfs.VirtualFile
VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment.
Using VFS adapter org.apache.ibatis.io.DefaultVFS
Find JAR URL: file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/pojo
Not a JAR: file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/pojo
Reader entry: student.class
Listing file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/pojo
Find JAR URL: file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/pojo/student.class
Not a JAR: file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/pojo/student.class
Reader entry: ���� < :
Checking to see if class com.dwx.pojo.student matches criteria [is assignable to Object]
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Find JAR URL: file:/E:/java/MyBatisStudy/Mybatis03/target/test-classes/com/dwx/mapper
Not a JAR: file:/E:/java/MyBatisStudy/Mybatis03/target/test-classes/com/dwx/mapper
Reader entry: test.class
Listing file:/E:/java/MyBatisStudy/Mybatis03/target/test-classes/com/dwx/mapper
Find JAR URL: file:/E:/java/MyBatisStudy/Mybatis03/target/test-classes/com/dwx/mapper/test.class
Not a JAR: file:/E:/java/MyBatisStudy/Mybatis03/target/test-classes/com/dwx/mapper/test.class
Reader entry: ���� < U
Find JAR URL: file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/mapper
Not a JAR: file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/mapper
Reader entry: StudentMapper.class
Reader entry: StudentMapper.xml
Listing file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/mapper
Find JAR URL: file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/mapper/StudentMapper.class
Not a JAR: file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/mapper/StudentMapper.class
Reader entry: ���� <   com/dwx/mapper/StudentMapper  java/lang/Object getStudentList ()Ljava/util/List; Signature *()Ljava/util/List<Lcom/dwx/pojo/student;>;
Find JAR URL: file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/mapper/StudentMapper.xml
Not a JAR: file:/E:/java/MyBatisStudy/Mybatis03/target/classes/com/dwx/mapper/StudentMapper.xml
Reader entry: <?xml version="1.0" encoding="UTF-8" ?>
Checking to see if class com.dwx.mapper.test matches criteria [is assignable to Object]
Checking to see if class com.dwx.mapper.StudentMapper matches criteria [is assignable to Object]
Opening JDBC Connection
Created connection 473153915.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1c33c17b]
==> Preparing: select * from mybatis.student
==> Parameters:
<== Columns: id, name, password
<== Row: 1, 张三, welcome
<== Row: 2, 李四, welcome
<== Row: 4, 王五, 123456
<== Row: 17, dwx, welcome
<== Row: 100, 李一百, welcome
<== Total: 5
student{id=1, name='张三', pwd='welcome'}
student{id=2, name='李四', pwd='welcome'}
student{id=4, name='王五', pwd='123456'}
student{id=17, name='dwx', pwd='welcome'}
student{id=100, name='李一百', pwd='welcome'}

Process finished with exit code 0

这种日志的特点在于:

  • 使用简单 能实现基本功能
  • 只在控制台输出 不可以DIy 不可以控制输出格式

LOG4J的使用

LOG4J应该是使用更加广泛地,但是他的使用需要进行配置,使用起来有点麻烦

LOG4J的使用步骤:

  • 导入LOG4J的依赖
  • 在resource文件下新增一个配置文件(log4j.properties)
  • 编写log4j配置文件(网上搜 不用记)(会在博客中写的)
  • 设置log4j为日志的实现
  • 使用log4j

导入LOG4J的依赖

1
2
3
4
5
6
7
8
<dependencies>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>

在子程序的pom.xml文件中配置

在resource文件下新增一个配置文件(log4j.properties)

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
# priority  :debug<info<warn<error
#you cannot specify every priority with different file for log4j
log4j.rootLogger=debug,stdout,info,debug,warn,error

#console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= [%d{yyyy-MM-dd HH:mm:ss a}]:%p %l%m%n
#info log
log4j.logger.info=info
log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
log4j.appender.info.DatePattern='_'yyyy-MM-dd'.log'
log4j.appender.info.File=./logs/log.log
log4j.appender.info.Append=true
log4j.appender.info.Threshold=INFO
log4j.appender.info.layout=org.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
#debug log
log4j.logger.debug=debug
log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
log4j.appender.debug.DatePattern='_'yyyy-MM-dd'.log'
log4j.appender.debug.File=./logs/log.log
log4j.appender.debug.Append=true
log4j.appender.debug.Threshold=DEBUG
log4j.appender.debug.layout=org.apache.log4j.PatternLayout
log4j.appender.debug.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
#warn log
log4j.logger.warn=warn
log4j.appender.warn=org.apache.log4j.DailyRollingFileAppender
log4j.appender.warn.DatePattern='_'yyyy-MM-dd'.log'
log4j.appender.warn.File=./logs/log.log
log4j.appender.warn.Append=true
log4j.appender.warn.Threshold=WARN
log4j.appender.warn.layout=org.apache.log4j.PatternLayout
log4j.appender.warn.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
#error
log4j.logger.error=error
log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.DatePattern='_'yyyy-MM-dd'.log'
log4j.appender.error.File =./logs/log.log
log4j.appender.error.Append = true
log4j.appender.error.Threshold = ERROR
log4j.appender.error.layout = org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n

设置log4j为日志的实现

在核心配置文件中写

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

使用log4j

使用log4j有两种使用办法:

  • 直接使用
  • 编写使用方法

直接使用

在进行过以上的操作时,直接在操作类中写Logger logger = Logger.getLogger("测试方法类.class")

直接使用即可

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
package com.dwx.mapper;

import com.dwx.pojo.student;
import com.dwx.untils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;

import java.util.List;

public class test {
//注意 此处导包要导Apache的包
Logger logger = Logger.getLogger(test.class);

@Test
public void getStudentListTest(){
//首先需要获取到 mapper
//以下的操作都是固定的 不需要进行任何改变
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<student> studentList = mapper.getStudentList();
for (student student : studentList) {
System.out.println(student.toString());
}

}
}

注意:创建Logger 导包是一定要导Apache log4j的包

在运行后,会产生一个logs文件,里边有log日志

文件的产生

文件中的内容和在控制台中输出的内容一致

文件中的内容

使用测试方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.dwx.mapper;

import com.dwx.pojo.student;
import com.dwx.untils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;

import java.util.List;

public class test {
//注意 此处导包要导Apache的包
Logger logger = Logger.getLogger(test.class);
@Test
public void log4jTest(){
logger.info("###################infor#################");
logger.debug("##################debug#################");
logger.error("##################error##################");
}
}

这样使用的好处是,在log文件中只会出现我们设置的这几个数据

控制台中的输出

1
2
3
4
com.dwx.mapper.test,log4jTest
[2022-01-11 21:01:04 下午]:INFO com.dwx.mapper.test.log4jTest(test.java:30)###################infor#################
[2022-01-11 21:01:04 下午]:DEBUG com.dwx.mapper.test.log4jTest(test.java:31)##################debug#################
[2022-01-11 21:01:04 下午]:ERROR com.dwx.mapper.test.log4jTest(test.java:32)##################error##################

log.log中的输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2022-01-11 21:01:04 下午 [Thread: main][ Class:com.dwx.mapper.test >> Method: com.dwx.mapper.test.log4jTest(test.java:30) ]
INFO:###################infor#################
2022-01-11 21:01:04 下午 [Thread: main][ Class:com.dwx.mapper.test >> Method: com.dwx.mapper.test.log4jTest(test.java:30) ]
INFO:###################infor#################
2022-01-11 21:01:04 下午 [Thread: main][ Class:com.dwx.mapper.test >> Method: com.dwx.mapper.test.log4jTest(test.java:31) ]
DEBUG:##################debug#################
2022-01-11 21:01:04 下午 [Thread: main][ Class:com.dwx.mapper.test >> Method: com.dwx.mapper.test.log4jTest(test.java:32) ]
ERROR:##################error##################
2022-01-11 21:01:04 下午 [Thread: main][ Class:com.dwx.mapper.test >> Method: com.dwx.mapper.test.log4jTest(test.java:32) ]
ERROR:##################error##################
2022-01-11 21:01:04 下午 [Thread: main][ Class:com.dwx.mapper.test >> Method: com.dwx.mapper.test.log4jTest(test.java:32) ]
ERROR:##################error##################
2022-01-11 21:01:04 下午 [Thread: main][ Class:com.dwx.mapper.test >> Method: com.dwx.mapper.test.log4jTest(test.java:32) ]
ERROR:##################error##################

mybatis结果集映射

mybatis结果集映射

结果集映射(resultType)用来解决我们实体类中的参数名与数据库中列名不一致的问题。

当我们的实体类的参数名与数据库中的列名不一致是 就会发生查询错误

实体类的参数名与数据库中的列名不一致

此时的查询结果

错误的查询结果

我们可以发现 相同的查询正确,但是错误的查询的是null 查询不到

产生错误的原因

1
2
3
4
5
6
7
<select id="getStudentList" resultType="student">
select * from mybatis.student
</select>
<!--这个SQL等共同于-->
<select id="getStudentList" resultType="student">
select id,name,password from mybatis.student
</select>

可以看到 在student里根本没有查询到的password参数。因此产生了错误。

解决方法:

  • 使用别名
  • 结果集映射

使用别名

1
2
3
<select id="getStudentList" resultType="student">
select id,name,password as pwd from mybatis.student
</select>

这样就能直接查询了 但是这种方法是十分基础的,写的代码数量多。

结果集映射(resultType)

使用结果集映射 是在接口类的实现的mapper文件中操作,而不是和我们原来在核心配置文件中操作

1
2
3
4
5
6
7
8
9
10
<mapper namespace="com.dwx.mapper.StudentMapper">
<resultMap id="StudentMap" type="student">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="password" property="pwd"/>
</resultMap>
<select id="getStudentList" resultMap="StudentMap">
select * from mybatis.student
</select>
</mapper>

元素分析:

column:“列”,是指数据库中的字段的列名

property:“属性”,是指实体类中的属性

可以把每个参数都进行映射,也可以只对实体类中的参数与数据库中列名不同的进行映射

mybatis配置解析之映射

mybatis配置解析之映射

介绍:映射(mappers)即,我们之前说的每一个接口的xml文件必须在核心配置文件中“注册”

MapperRegistry:注册绑定我们的Mapper文件

文章源:mappers(映射器)

mybatis映射我们具体使用的有三种方法:

  1. 对xml文件进行映射
  2. 对接口类进行映射
  3. 对接口类所在的包进行映射

对xml文件进行映射

即注册时使用的是Mapper接口文件的实现xml文件

1
2
3
<mappers>
<mapper resource="com/dwx/mapper/StudentMapper.xml"/>
</mappers>

这种映射方式对两个文件的位置没有要求 可以在任何位置创建xml文件

对接口类进行映射

即对接口类进行注册

1
2
3
<mappers>
<mapper class="com.dwx.mapper.StudentMapper"/>
</mappers>

这种映射方式要求:

  • 接口类和我们的实现xml文件(mapper)必须在同一个包下
  • 接口类和我们的实现xml文件(mapper)必须同名

否则就会报错,找不到我们的文件

文件的位置

对接口类所在的包进行映射

1
2
3
<mappers>
<package name="com.dwx.mapper"/>
</mappers>

这种映射方式要求:

  • 接口类和我们的实现xml文件(mapper)必须在同一个包下
  • 接口类和我们的实现xml文件(mapper)必须同名

否则就会报错,找不到我们的文件

文件的位置

mybatis配置解析之别名

mybatis配置之别名

配置_MyBatis中文网

别名

使用别名的意义:能够在xml使用用java中编写的实体类是降低编写代码的冗余性。(全部路径的包名可以不用写了)

实际上就是给java中的实体类编写一个短的名字

使用别名的方法

命名别名可以大致分为两个方法:一、把一个个实体类命名成别名。二、直接引入pojo包 把这个包中的所有实体类都命名成别名;

使用别名的方法:在核心配置文件(mybatis-config.xml)中配置,在这个核心文件中配置过得xml文件中直接使用。

在配置别名时,需要注意的是。这个xml配置文件的标签的使用有先后顺序,不能随意位置放置。

将一个个实体类命名成别名

1
2
3
4
5
6
7
<!--在这里将我们创建的实体类进行别名-->
<!--在核心配置文件中配置别名-->
<!--在下边mapper中注册的xml中就能使用这个别名了-->
<!--这种方法是一下子别名一个实体类-->
<typeAliases>
<typeAlias alias="Student" type="com.dwx.pojo.student"/>
</typeAliases>

上述是xml中的配置

在配置好的xml中可以直接使用:

1
2
3
4
5
<mapper namespace="com.dwx.mapper.StudentMapper">
<select id="getStudentList" resultType="Student">
select * from mybatis.student
</select>
</mapper>

这种方法的特点:

  • 在实体类少时可以使用(方便),但是实体类多了以后就十分麻烦
  • 别名可以DIY 可以在alias后随便设置别名

将实体类的包直接命名成别名

1
2
3
4
<!--也可以直接一下子导入一个实体类的包 这样使用实体类的类名(首字母小写)作为它的别名-->
<typeAliases>
<package name="com.dwx.pojo"/>
</typeAliases>

这种情况下,在配置好的xml直接使用你引入的这个包中的实体类的类名(首字母小写)

1
2
3
4
5
<mapper namespace="com.dwx.mapper.StudentMapper">
<select id="getStudentList" resultType="student">
select * from mybatis.student
</select>
</mapper>

这种方式的特点:

  • 在实体类多时使用十分方便
  • 别名不能DIY——为实体类的类名(首字母小写)

但是说这种方法不能DIY别名是十分不严谨的,如果和注解结合使用就能实现类名的DIY

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
@Alias("hello")
public class student {
private int id;
private String name;
private String password;

//无参构造
public student() {
}

//有参构造
public student(int id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}

//get和set方法
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 String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}

当实体类使用Alias("别名")后,就能在引入这个实体类所在的包后使用这个别名作为别名使用

1
2
3
4
5
<mapper namespace="com.dwx.mapper.StudentMapper">
<select id="getStudentList" resultType="hello">
select * from mybatis.student
</select>
</mapper>

mybatis配置解析

mybatis配置解析

入门_MyBatis中文网

在介绍mybatis配置解析前 首先我们复习一下

创建一个使用mybatis框架的子项目的方法:

  1. 在父项目下新建一个Module(普通的maven项目)
  2. 在main、resource下写核心配置文件(mybatis-config.xml)
  3. 写工具类(untils)
  4. 写实体类(pojo)
  5. 写接口类(Mapper)

配置解析

核心配置文件(mybatis-config.xml)

这个核心配置文件的基本结构为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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 resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>

环境变量(environments)

基本结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>
<environment id="test">
<transactionManager type="JDBC"/>
<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>

environments这里是写的复数,因此其实可以写很多套environment,但能使用一套 即default参数指向的那套

属性(properties)

如在environment里就有property

properties里有三种引入方法

第一种 不引入 直接在enviroment里写

1
2
3
4
5
6
7
8
9
<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?useUnicode=true&amp;characterEnconding=utf8&amp;useSSL=true"/>
<property name="username" value="dwx"/>
<property name="password" value="123456"/>
</dataSource>
</environment>

第二种 在xml中的<properties></properties>键值对里写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<properties>
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEnconding=utf8&amp;useSSL=true"/>
<property name="username" value="dwx"/>
<property name="password" value="123456"/>
</properties>

<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>

当然 此时 我们可以看到 在使用配置参数时 就直接使用${}引入

第三种 在db.properties中编写 在<properties></properties>中引入

db.properties:

1
2
3
4
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEnconding=utf8&useSSL=true
username = dwx
password = 123456

mybaties-config.xml:

1
2
3
4
5
6
7
8
9
10
11
12
<properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>

他们的基本结构是:

两个文件的结构

我们注意 当同时存在外部引入和内部参数时,外部引入的优先级更高

mybatis增删改查操作基础


由于mybatis就是对永久层简化的一种操作,器主要的操作就是对数据库的增删改查,因此今天我将介绍mybatis增删改查操作的基础

增删改查操作实现的步骤

与Jdbc相同,mybatis的增删改查工作也是有很多的共性的,区别只存在于sql语句的编写

共同步奏:

  1. 编写mapper接口类 创建方法
  2. 编写mapper接口类的实现xml文件
  3. 使用

SELECT 查询

查询可以分为两种:1.查询全部内容,2.通过参数参训

查询全部内容(无参查询)

1
2
3
4
5
6
<!--与Dao类的实现类一样 这里是写sql语句-->
<!--id指的是我们调用这个sql使用的名字,可以理解为BaseDaoImp的方法名-->
<!--resultType表示返回的数据的类型 如果是自己创建的类 需要填写整个路径-->
<select id="getList" resultType="com.dwx.pojo.student">
select * from mybatis.student
</select>

元素分析:

  • id与mapper抽象类中的方法相同
  • resulttype指的是返回值类型 如果是基本数据类型直接写基本数据类型,如果是自定义数据类型就将全部的路径都写下来

查询部分内容(有参查询)

1
2
3
4
5
<!--parameterType表示参数类型-->
<!--通过特定的参数查询,一定要写好参数类型 一般查收农户类型直接写 自定义的参数类型就写参数的全路径-->
<select id="getStudentById" resultType="com.dwx.pojo.student" parameterType="int">
select * from mybatis.student where id = #{id}
</select>

元素分析:

  • id与mapper抽象类中的方法相同
  • resulttype指的是返回值类型 如果是基本数据类型直接写基本数据类型,如果是自定义数据类型就将全部的路径都写下来
  • parameterType表示参数类型 在这个xml文档是 通过#{参数名} 来获得参数的 获得的参数来自id指的方法

INSERT 插入

插入即增加

1
2
3
4
<!--我们可以直接把参数类型中的子类型提取出来使用-->
<insert id="InsertStudent" parameterType="com.dwx.pojo.student">
insert into mybatis.student (id,name,password) values(#{id},#{name},#{password})
</insert>

注意:插入操作的实现是需要提交事务的,写到实现方法时会再次强调

插入没有返回值类型

  • id与mapper抽象类中的方法相同
  • parameterType表示参数类型 在这个xml文档是 通过#{参数名} 来获得参数的 获得的参数来自id指的方法

DELETE 删除

1
2
3
4
<!--删除操作-->
<delete id="DeleteStudent" parameterType="int">
delete from mybatis.student where id = #{id}
</delete>

删除没有返回值类型

  • id与mapper抽象类中的方法相同
  • parameterType表示参数类型 在这个xml文档是 通过#{参数名} 来获得参数的 获得的参数来自id指的方法

UPDATE SET 修改

更新 设置 即为修改

1
2
3
4
<!--修改用户信息-->
<update id="UpdateStudent" parameterType="com.dwx.pojo.student">
update mybatis.student set name = #{name},password = #{password} where id = #{id}
</update>

修改没有返回值类型

  • id与mapper抽象类中的方法相同
  • parameterType表示参数类型 在这个xml文档是 通过#{参数名} 来获得参数的 获得的参数来自id指的方法

mapper/dao 抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.dwx.dao;

import com.dwx.pojo.student;

import java.util.List;

//编写一个抽象的DAO接口
public interface UserDao {
//编写这个接口需要的方法
//查询所有的用户
List<student> getList();
//通过id查询用户
student getStudentById(int id);
//增加用户
void InsertStudent(student student);
//修改用户信息
void UpdateStudent(student student);
//通过id删除用户信息
void DeleteStudent(int 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
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
package com.dwx.dao;

import com.dwx.pojo.student;
import com.dwx.untils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest {
@Test
public void test(){
//调用我们的myBatisUtils来获得是SqlSession
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
//sqlSession进行操作
//通过反释来获得UserMapper
UserDao mapper = sqlSession.getMapper(UserDao.class);
//获得的mapper对象就能调用“id”,来实现操作了
List<student> list = mapper.getList();
for (student student : list) {
System.out.print(student.getId());
System.out.print(student.getName());
System.out.println(student.getPassword());
}
sqlSession.close();

}
//通过参数查询的测试方法
@Test
public void getStudentById(){
//这些都是固定格式
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
//sqlSession获得联结
UserDao mapper = sqlSession.getMapper(UserDao.class);
student studentById = mapper.getStudentById(2);
System.out.println(studentById);
System.out.println(studentById.getId()+studentById.getName()+studentById.getPassword());


sqlSession.close();
}
@Test
public void InsertStudnet(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
//获得了sqlSession就需要进行联结获得mapper
UserDao mapper = sqlSession.getMapper(UserDao.class);
//通过mapper对象来进行操作
mapper.InsertStudent(new student(4,"王五","123456"));
//对于需要对数据库进行改动的如:“增删改” 都系要提交事物
sqlSession.commit();
//关闭sqlsession
sqlSession.close();
}
@Test
public void update(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();

UserDao mapper = sqlSession.getMapper(UserDao.class);
mapper.UpdateStudent(new student(3,"李四","123456"));
//注意必须提交事务
sqlSession.commit();
sqlSession.close();
}
@Test
public void delete(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
mapper.DeleteStudent(3);
//提交事务
sqlSession.commit();
sqlSession.close();
}
}

注意,JDBC中有链接(getconnection)就完成了事务的提交,但是mybatis需要手动提交事务。

就是在执行完对数据库有改动的操作(增删改)后需要加一个语句sqlSession.commit()

  • Copyrights © 2015-2022 dwx
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信