MyBatis

第一章 框架的概述

1、三层架构

MVC:web开发中,使用MVC架构模式,M:数据,V:视图,C:控制器

C控制器:接收请求,调用service对象,显示请求的处理结果,当前使用servlet作为控制器

V视图:现在使用jsp,html,css,js。显示请求的处理结果,把M中的数据显示出来

M数据:来自数据库mysql,来自文件,来自网络

MVC作用:

1)实现解耦合

2)让MVC各负其职

3)使得系统扩展性更好,更容易维护

三层架构:

1、界面层(视图层):接收用户的请求,调用service,显示请求的处理结果的,包含了jsp、html、servlet等对象,对应的包controller

2、业务逻辑层:处理业务逻辑,使用算法处理数据的,把数据返回给界面层,对应的是service包,和包中的很多的XXXservice类,例如:StudentService、OrderService、ShopService

3、持久层(数据库访问层):访问数据库,或者读取文件,访问网络。获取数据,对应的包是dao,dao包中很多的StudentDao,OrderDao,ShopDao等等

2、三层架构请求的处理流程

用户发起请求——>界面层——>业务逻辑层——>持久层——>数据库(MySQL)

3、为什么要使用这三层?

1、结构清晰、耦合度低、各层分工明确

2、可维护性高,可扩展性高

3、有利于标准化

4、开发人员可以只关注整个结构中的其中某一层的功能实现

5、有利于各层逻辑的复用

4、三层架构模式和框架

每一层对应着一个框架

1)界面层——SpringMVC框架

2)业务层——Spring框架

3)持久层——MyBatis框架

MyBatis框架:

MyBatis是一个优秀的基于java的持久层框架,内部封装了jdbc,开发者只需要关注sql语句本身,而不需要处理加载驱动、创建连接、创建statement、关闭连接

Spring框架:

Spring框架为了解决软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前非常复杂的企业级开发。Spring解决了业务对象,功能模块

SpringMVC框架:

SpringMVC属于SpringFrameWork3.0版本加入的一个模块,为Spring框架提供了构建Web应用程序的能力

5、框架

框架(framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构建实例间交互的方法:另一种认为,框架是可被应用开发者定制的应用骨架、模板

简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。从另一个角度来说框架是一个舞台,你在舞台上做表演。在框架基础上加入你要完成的功能

框架是安全的,可复用的,不断升级的软件

框架:就是一个软件,完成了部分的功能,软件中的类和类之间的方法调用都已经规定好了,通过这些可以完成某些功能,框架看做是模板

框架是对某一个方面有用的,不是全能的

6、框架解决的问题

1)框架能实现技术的整合

2)提供开发的效率,降低难度

​ 框架要解决的最重要的一个问题是技术整合,在J2EE的框架中,有着各种各样的技术,不同的应用,系统使用不同的技术解决问题,需要从J2EE中选择不同的技术,而技术自身的复杂性,有导致更大的风险。企业在开发软件项目时,主要目的是解决业务问题,既要求企业负责技术本身,又要求解决业务问题,这是大多数企业不能完成的,框架把相关的技术融合在一起,企业开发可以集中在业务领域方面

​ 另一个方面可以提供开发的效率

7、JDBC访问数据库的优缺点

优点:1、直观、好理解

缺点:

1、创建很多对象Connection,Statement,ResultSet

2、注册驱动

3、执行sql语句

4、把ResultSet转为Student,List集合

5、关闭资源

6、sql语句和业务逻辑代码混在一起

8、MyBatis框架

什么是MyBatis?是一个持久层框架

MyBatis框架:MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到GitHub

MyBatis解决的问题:减轻使用JDBC的复杂性,不用编写重复的创建Connection,Statement;不用编写关闭资源代码

直接使用java对象,表示结果数据,让开发者专注SQL的处理,其它分心的工作由MyBatis代劳

MyBatis可以完成:

1、注册数据库的驱动,例如Class.forName(“com.mysql.cj.jdbc.Driver”)

2、创建JDBC中必须使用的Connection,Statement,ResultSet对象

3、从xml中获取sql,并执行sql语句,把ResultSet结果转换为java对象

4、关闭资源

ResultSet.close(),Statement.close(),Connection.close()

MyBatis可以操作数据库,对数据执行增删改查,看做是高级的jdbc,解决jdbc的缺点

第二章 MyBatis框架快速入门

2.1 入门案例

MyBatis开发准备

​ 下载MyBatis:https://github.com/mybatis/mybatis-3/releases

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>

搭建MyBatis开发环境,实现第一个案例

​ (1)创建mysql数据库和表

数据库名ssm;表名student

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4OJrUqAe-1642483473066)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828134238544.png)]

(2)新建maven项目

(3)修改pom.xml

1)加入依赖mybatis依赖,mysql驱动,junit

2)在<build>加入资源插件

(4)创建实体类Student,定义属性,属性名和列名保持一致

(5)创建Dao接口,定义操作数据库的方法

(6)创建xml文件(mapper文件),写sql语句

​ mybatis框架推荐是把sql语句和java语句分开

​ mapper文件:定义和dao接口在同一目录,一个表一个mapper文件

(7)创建mybatis的主配置文件(xml文件):有一个,放在resources目录下

​ 1)定义创建连接实例的数据源(DataSource)对象

​ 2)指定其他mapper文件的位置

(8)创建测试的内容

使用main方法,测试mybatis访问数据库

也可以使用junit访问数据库

<build>
    <resources>
      <!--资源插件:处理src/main/java目录中的xml-->
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
</build>
<?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="org.mybatis.example.BlogMapper">
    <select id="selectBlog" resultType="Blog">
        select * from Blog where id = #{id}
    </select>
</mapper>

约束文件:“http://mybatis.org/dtd/mybatis-3-mapper.dtd”

约束文件作用:定义和限制当前文件中可以使用的标签和属性,以及标签出现的顺序

mapper是根标签

namespace:命名空间,必须有值,不能为空,唯一值,推荐使用Dao接口的权限定名称,作用:参与识别sql语句的作用

在mapper里面可以写<insert>,<update>,<delete>,<select>标签

<insert>里面是insert语句,表示执行的insert操作

<update>里面是update语句

<delete>里面是delete语句

<select>里面是select语句

<!--    查询一个学生Student
        <select>:表示查询操作,里面是select语句
        id:要执行的sql语句的唯一标识,是一个自定义字符串,推荐使用dao接口中的方法名称
        resultType:告诉mybatis,执行sql语句,把数据赋值给哪个类型的java对象
        resultType的值现在使用的java对象的全限定名称
-->
    <select id="selectStudentById" resultType="org.example.mybatis.pojo.Student">
        select id,name,email,age from student where id=1001
    </select>

主配置文件

<?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"/>
<!--            配置数据源,创建Connection对象-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql//localhost:3306/ssm?useUnicode-true&amp;characterEncoding-utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="westos"/>
            </dataSource>
        </environment>
    </environments>
<!--    指定其他mapper文件的位置,目的:找到其他文件的sql语句-->
    <mappers>
<!--        使用mapper的resource属性指定mapper文件的路径,这个路径是从target/classes路径开启的-->
<!--        使用注意:resource="mapper"文件的路径,使用/分隔路径-->
<!--        一个mapper resource指定一个mapper文件-->
        <mapper resource="org/example/mybatis/dao/StudentDao.xml"/>
    </mappers>
</configuration>
public class MyTest {
    @Test
    public void testSelectStudentById() throws IOException {
        //调用mybatis某个对象的方法,执行mapper文件中的sql语句
        //mybatis核心类:SqlSessionFactory

        //1、定义mybatis主配置文件的位置,从类路径开始的相对路径
        String config = "mybatis.xml";
        //2、读取主配置文件,使用mybatis框架中的Resources类
        InputStream inputStream = Resources.getResourceAsStream(config);
        //3、创建SqlSessionFactory对象,使用SqlSessionFactoryBuilder类
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //4、获取SqlSession对象
        SqlSession session = factory.openSession();
        //5、指定要执行的sql语句的id
        //sql的id = namespace+"."+select|update|insert|delete标签的id属性值
        String sqlId = "org.example.mybatis.dao.StudentDao" + "." + "selectStudentById";
        //6、通过SqlSession的方法,执行sql语句
        Student student = session.selectOne(sqlId);

        System.out.println("student = " + student);
        //7、关闭SqlSession对象
        session.close();
    }
}

初次使用占位符

#{studentId}:占位符,表示从java程序中传入过来的数据

<select id="selectStudentById" resultType="org.example.mybatis.pojo.Student">
        select id,name,email,age from student where id=#{studentId}
</select>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r5qToowf-1642483473067)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828155936395.png)]

insert需要提交事务

日志功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vJ7DNfFk-1642483473068)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828160502771.png)]

2.2 概念

自动提交:当你的sql语句执行完毕后,提交事务,数据库更新操作直接保存到数据库

手动提交事务:在你需要提交事务的位置,执行方法,执行事务或者回滚事务

mybatis默认执行sql语句是手工提交事务模式,在做insert,update,delete后需要提交事务

session.commit()

如果传入给mybatis是一个java对象,使用#{属性名}获取此属性的值

属性值放到#{}占位符的位置,mybatis执行此属性对应的getXXX()

例如#{id},执行getId();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U5qFG4bx-1642483473069)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828185733066.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iDjDTugm-1642483473070)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828185806214.png)]

2.3Mybatis的一些重要对象

1)Resources:mybatis框架中的对象,一个作用读取主配置信息

2)SqlSessionFactoryBuilder:负责创建SqlSessionFactory对象

3)SqlSessionFactory:重要对象

SqlSessionFactory是重量级对象:创建此对象需要使用更多的资源和时间,在项目中有一个就可以了

SqlSessionFactory接口:作用是SqlSession的工厂,就是创建SqlSession对象

DefaultSessionFactory实现类

public class DefaultSqlSessionFactory implements SqlSessionFactory{}

SqlSessionFactory接口中的方法

openSession():获取一个默认的SqlSession对象,默认是需要手工提交事务的

openSession(boolean):boolean参数表示是否自动提交事务

true:创建一个自动提交事务的SqlSession

false:等同于没有参数的openSession

4)SqlSession对象

SqlSession对象是通过SqlSessionFactory获取的,SqlSession本身是接口

DefaultSqlSession实现类

public class DefaultSqlSession implements SqlSession{}

SqlSession作用是提供了大量的执行sql语句的方法

selectOne:执行sql语句,最多得到一行记录,多余一行是错误
selectList:执行sql语句,返回多行数据
selectMap:执行sql语句,得到一个Map结果
insert:执行insert语句
update:执行update语句
delete:执行delete语句
commit:提交事务
rollback:回滚事务

注意SqlSession对象不是线程安全的,使用的步骤:

①:在方法的内部,执行sql语句之前,先获取SqlSession对象

②:调用SqlSession的方法,执行sql语句

③:关闭SqlSession对象,执行SqlSession.close()

mybatis的底层是jdbc

2.4使用工具类和模板

创建mapper文件的模板

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fKaa5YkL-1642483473071)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828200448855.png)]

加号添加自定义模板

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtEHgKz7-1642483473073)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828201056999.png)]

创建主配置文件的模板

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Mqrea8w-1642483473074)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828201834355.png)]

创建工具类MyBatisUtil

/**
 * 工具类:创建SqlSession对象
 */
public class MyBatisUtil {
    private static SqlSessionFactory factory = null;
    static {
        String config = "mybatis.xml";
        try {
            InputStream inputStream = Resources.getResourceAsStream(config);
            factory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    //创建方法,获取SqlSession对象
    public static SqlSession getSqlSession(){
        SqlSession session = null;
        if (factory != null){
            session = factory.openSession();//openSion(true);
        }
        return session;
    }
}
@Test
    public void testSelectById(){
        //1、获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2、指定sqlid
        String sqlId = "org.example.mybatis.dao.StudentDao" + "." + "InsertStudent";
        //3、执行SqlSession的方法,执行sql语句
        session.insert(sqlId,new Student(1005,"hhahhvsah","hahsak@qq.com",78));
        session.commit();
        //4、关闭SqlSession对象
        session.close();
    }

查询所有

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HHc0GvQ1-1642483473074)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828204628579.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gJi0Vl0N-1642483473076)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828204653535.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LCvAxEFs-1642483473076)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828204726087.png)]

使用传统的dao执行sql

public class StudentDaoImpl implements StudentDao {
    @Override
    public Student selectStudentById(Integer id) {
        SqlSession session = MyBatisUtil.getSqlSession();
        String sqlId = "org.example.mybatis.dao.StudentDao" + "."+ "selectStudentById";
        Student student = session.selectOne(sqlId, id);
        session.close();
        return student;
    }

    @Override
    public int InsertStudent(Student student) {
        SqlSession session = MyBatisUtil.getSqlSession();
        String sqlId = "org.example.mybatis.dao.StudentDao" + "."+"InsertStudent";
        int hah = session.insert(sqlId, student);
        session.commit();
        session.close();
        return hah;
    }

    @Override
    public List<Student> selectAllStudent() {
        SqlSession session = MyBatisUtil.getSqlSession();
        String sqlId = "org.example.mybatis.dao.StudentDao" + "."+ "selectAllStudent";
        List<Student> students = session.selectList(sqlId);
        session.close();
        return students;
    }
}
public class StudentDaoImplTest extends TestCase {

    private StudentDaoImpl studentDao = new StudentDaoImpl();

    public void testSelectStudentById() {
        Student student = studentDao.selectStudentById(1002);
        System.out.println("student = " + student);
    }

    public void testInsertStudent() {
        int i = studentDao.InsertStudent(new Student(1006, "ahhvsah", "hsak@qq.com", 78));
        System.out.println("i = " + i);
    }

    public void testSelectAllStudent() {
        List<Student> students = studentDao.selectAllStudent();
        for (Student stu:students){
            System.out.println("stu = " + stu);
        }
    }
}

测试方法中:调用dao的方法

Student student = dao.selectById(1002);

1)dao:通过反射能够得到全限定类型名称

dao是StudentDao类型的,全限定类型名称org.example.mybatis.dao.StudentDao

2)selectById:dao中的方法名称,方法名称就是mapper文件中标签的id

通过dao.selectById()能得到sqlId=“com.example.mybatis.dao.StudentDao.selectById”;

3)确定调用SqlSession的那个方法

1、根据dao接口的方法返回类型,如果返回是一个对象,例如Student,调用SqlSession.selectOne();

如果dao接口中的方法返回List,调用SqlSession的selectList();

2、根据mapper文件中的标签,如果标签是<insert>,调用SqlSession.insert()方法

mybatis代理的说明

mybatis框架,发现使用dao的方法调用能确定执行sql语句的必要信息,mybatis简化dao对象的实现

由mybatis框架在程序执行期间,根据你的Dao接口,创建一个内存中的接口的实现类对象

mybatis把这个技术叫做dao技术(动态代理,dao的动态代理)

dao代理技术:由mybatis创建StudentDao接口的实现类StudentDaoImpl,使用框架创建的StudentDaoImpl代替你自己手动实现的StudentImpl类的功能,不用开发人员写dao接口的实现类

使用dao的代理要求:

1、mapper文件中的namespace:必须是dao接口的全限定名称

2、mapper文件中标签的id是dao接口中的方法名称(一模一样的)

2.5dao代理

mybatis提供代理:mybatis创建Dao接口的实现类对象,完成对sql语句的执行,mybatis创建一个对象代替你的dao实现类功能

使用mybatis代理要求

1)mapper文件中的namespace一定是dao接口的全限定名称

2)mapper文件中标签的id是dao接口方法名称

mybatis代理实现方式

使用SqlSession对象的方法getMapper(dao.class)

例如:现在有StudentDao接口

SqlSession session = MyBatisUtils.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.calss);
Student student = dao.selectById(1001);

//上面代码中
StudentDao dao = session.getMapper(StudentDao.calss);
//等同于
StudentDao dao = new StudentDaoImpl();
@Test
    public void testInserttStudentById() throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        Student student = dao.selectStudentById(1003);
        System.out.println("student = " + student);
        session.close();
    }

不需要StudentDao实现类了

@Test
public void testSelectById(){
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    int i = dao.InsertStudent(new Student(1007, "jajc", "jdnacj@qq.com", 18));
    System.out.println("i = " + i);
    session.commit();
    session.close();
}

@Test
public void testSelectAllStudent(){
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    List<Student> students = dao.selectAllStudent();
    students.forEach(student -> {
    System.out.println("student = " + student);
    });
    session.close();
}

(1)去掉Dao接口的实现类

(2)getMapper获取代理对象

​ 只需调用SqlSeesion的getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定Dao接口类的class值

SqlSession session = factory.openSession();
StudentDao dao = session.getMapper(StudentDao.class);

使用工具类:

StudentDao studentDao = MyBatisUtil.getSqlSession().getMapper(StudentDao.class);

(3)使用Dao代理对象方法执行sql语句

第三章 mybatis的dao代理

3.2 深入理解参数

从java代码中把参数传递到mapper.xml文件

理解参数是:通过java程序把数据传入到mapper文件中的sql语句

参数主要是指dao接口方法的形参

3.2.1 parameterType

parameterType:接口中方法参数的类型,类型的完全限定名或别名。这个属性是可选的,因为mybatis可以推断出具体传入语句的参数,默认值为未设置(unset)。接口中方法的参数从java代码传入到mapper文件的sql语句

<select>,<insert>,<update>,<delete>都可以使用parameterType指定类型

parameterType:表示参数的类型,指定dao方法的形参数据类型,这个形参的数据类型给mybatis使用,mybatis在给sql语句的参数赋值时使用,PreparedStatement.setXXX(位置,值)

parameterType:指定dao接口形参的类型,这个属性的值可以使用java类型的全限定名称或者mybatis定义的别名

<select id="selectById" parameterType="java.lang.Integer" resultType="org.example.mybatis.pojo.Student">
	select id,name,email,age from student where id=#{studentId}
</select>

mybatis执行的sql语句:select id,name,email,age from student where id=?

?是占位符,使用jdbc中的PreparedStatement执行这样的sql语句

PreparedStatement pst = conn.preparedStatement("select id,name,email,age from student where id=?")

给?位置赋值

参数是Integer,执行pst.setInt(1,1005);

参数是String,执行pst.setString(1,“1005”);

第一种用法:java类型的全限定类型名称 parameterType=”java.lang.Integer"

第二种用法:mybatis定义的java类型的别名

官方文档

parameterType可以不写,mybatis通过反射机制可以获取dao接口方法参数的类型

3.2.2 一个简单参数

Dao接口中方法的参数只有一个简单类型(java基本类型和String),占位符#{任意字符},和方法的参数名无关

接口方法:Student selectById(int id);

mapper文件:获取这个参数值,使用#{任意字符}

3.2.3 dao接口方法有多个简单类型的参数

@Param:命名参数,在方法的形参前面使用的,定义参数名,这个名称可以用在mapper文件中

dao接口,方法的定义

/**
 * 多个简单类型的参数
 * 使用@Param命名参数,注解是mybatis提供的
 * 位置:在形参定义的前面
 * 属性:value自定义的参数名称
*/
List<Student> selectByNameOrAge(@Param("myname") String name,
                                @Param("myage") Integer age);

mapper文件

<!--
	多个简单类型的参数
	当使用了@Param命名后,例如@Param("myname")
	在mapper中,使用#{命名的参数},例如#{myname}
-->
<select id="selectByNameOrAge" resultType="org.example.mybatis.pojo.Student">
	select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>

3.2.4 dao接口方法使用一个对象作为参数

方法的形参是一个java对象,这个java对象表示多个参数,使用对象的属性值作为参数使用

/**
 * 一个java对象作为参数(对象有属性,每个属性有set,get方法)
 */
List<Student> selectByObject(Student student);

mapper文件

<!--
	一个java对象作为方法的参数,使用对象的属性作为参数值使用
	简单的语法:#{属性名},mybatis调用对象的getXXX()方法获取属性值
-->
<select id="selectByObject" resultType="org.example.mybatis.pojo.Student">
	insert into student values (#{id},#{name},#{email},#{age})
</select>

<select id="selectByObject" resultType="org.example.mybatis.pojo.Student">
	select id,name,email,age from student where name=#{name} or age=#{age}
</select>

多个参数——使用对象

使用java对象传递参数,java的属性值就是sql需要的参数值,每一个属性就是一个参数

语法格式

#{property,javaType=java中数据类型名,jdbcType=数据类型名称}

javaType,jdbcType的类型MyBatis可以检测出来,一般不需要设置,常用格式#{property}

<select id="selectByObject" resultType="org.example.mybatis.pojo.Student">
	select id,name,email,age from student where name=#{name,javaType=java.lang.String,jdbcType=VARCHAR} or age=#{age,javaType=java.lang.Integer,jdbcType=INTEGER}
</select>

多个参数——按位置

参数位置从0开始,引用参数语法#{arg位置},第一个参数是#{arg0},第二个是#{arg1}

注意:mybatis-3.3版本和之前的版本使用#{0},#{1}方式,从mybatis3.4开始使用#{arg0}方式

接口方法:List<Student> selectByNameAndAge(String name,int age);

mapper文件:

<select id="selectByNameAndAge" resultType="org.example.mybatis.pojo.Student">
	select id,name,email,age from student where name=#{arg0} or age=#{arg1}
</select>

多个参数——使用Map

Map集合可以存储多个值,使用Map向mapper文件一次传入多个参数,Map集合使用String的key

Object类型的值存储参数,mapper文件使用#{key}引用参数值

例如:

Map<String,Object> data = new HashMap<String,Object>(){{
    put("myname","李力");
    put("myage",20);
}}

接口方法:

List<Student> selectStudentByMap(Map<String,Object> map);

在mapper文件中,获取map的值,是通过key获取的,语法:#{key}

<select id="selectByNameAndAge" resultType="org.example.mybatis.pojo.Student">
	select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>

更新

<update id="updateStudent">
	update student set name=#{name},email=#{email} where id=#{id}
</update>

#和$

#占位符:告诉mybatis使用实际的参数值代替,并使用PrepareStatement对象执行sql语句,#{…}代替sql语句的“?",这样做更安全,更迅速,通常也是首选做法

mapper文件

<select id="selectByNameAndAge" resultType="org.example.mybatis.pojo.Student">
	select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>

转为MyBatis的执行是:

String sql = "select id,name,email,age from student where id=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,1005);
ResultSet rs = ps.executeQuery();

#{}特点:

1)使用的PrepareStatement对象,执行sql对象,效率高

2)使用的PrepareStatement对象,能避免sql语句,sql语句执行更安全

3)#{}常常作为列值使用的,位于等号的右侧,#{}位置的值和数据类型有关的

$占位符:语法${字符}

mybatis执行${}占位符的sql语句

<select id="selectById" parameterType="integer"
        resultType="org.example.mybatis.pojo.Student">
	select id,name,email,age from student where id=${studentId}
</select>

${} 表示字符串连接,把sql语句的其他内容和${}内容使用字符串(+)连接的方式连在一起
String sql = "select id,name,email,age from student where id=” + "1001";

mybatis创建Statement对象,执行sql语句
Statement stmt = conn.createStatement(sql);
ResultSet rs = stmt.executeQuery();

${}的特点

1)使用Statement对象,执行sql语句,效率低

2)${}占位符的值,使用的字符串连接方式,有sql注入的风险,有代码安全问题

3)${}数据是原样使用的,不会区分数据类型

4)${}常用作表名或者列名,在能保证数据安全的情况下使用${}

//$占位符的使用,使用@Param命名
List<Student> querySudent(@Param("myname") String name);

使用$占位符表示表名或者列名

3.3 封装MyBatis输出结果

封装输出结果:MyBatis执行sql语句,得到ResultSet,转为java对象

3.3.1 resultType

resultType:执行sql得到ResultSet转换的类型,使用类型的完全限定名或别名,注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。resultType和resultMap,不能同时使用

resultType属性:在执行select时使用,作为<select>标签的属性出现的

resultType:表示结果类型,mysql执行sql语句,得到java对象的类型,它的值有两种1)java类型的全限定名称,2)使用别名

1)resultType表示自定义对象

<select id="selectByNameAndAge" resultType="org.example.mybatis.pojo.Student">
	select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>

resultType:现在使用java类型的全限定名称,表示的意思:mybatis执行sql,把ResultSet中的数据转为Student类型的对象。
mybatis会做以下操作:
1、调用org.example.mybatis.pojo.Student的无参数构造方法,创建对象
Student student = new Student();		//使用反射创建对象
2、同名的列赋值给同名的属性
student.setId(rs.getInt("id"));
student.setName(rs,getString("name"));
3、得到java对象,如果dao接口返回值是List集合,mybatis把student对象放入到List集合

所以执行Student mystudent = dao.selectById(1001);	得到数据库中id=1001这行数据
这行数据的列值,赋给了mystudent对象的属性,你能得到mystudent对象,就相当于是id=100这行数据

2)resultType表示简单类型

dao方法

long countStudent();

mapper文件

<!--    执行sql语句,得到的是一个值(一行一列)-->
    <select id="countStudent" resultType="java.lang.Long">
        select count(*) from student
    </select>

3)resultType为Map类型

sql的查询结果作为Map的key和value,推荐使用Map<Object,Object>

注意:Map作为接口返回值,sql语句的查询结果最多只能有一条记录,大于一条记录是错误

执行sql语句得到一个Map结构数据,mybatis执行sql,把ResultSet转为map

sql执行结果,列名做map的key,列值作为value

sql执行得到是一行记录,转为map结构是正确的

dao方法:

Map<Object,Object> selectReturnMap(int id);

mapper文件:

<select id="selectReturnMap" resultType="java.util.HashMap">
	select name,email,from student where id=#{studentId}
</select>

3.3.2 resultMap

resultMap可以自定义sql的结果和java对象属性的映射关系,更灵活的把列值赋值给指定属性

常用在列名和java对象属性名不一样的情况

用法:先定义,再使用

1、先定义resultMap标签,指定列名和属性名称对应关系

2、在select标签使用resultMap属性,指定上面定义的resultMap的id值

<!-- 定义resultMap
	id:给resultMap的映射关系起个名称,唯一值
	type:java类型的全限定名称
-->
<resultMap id="studentMap" type="org.example.mybatis.pojo.Student">
<!--        定义列名和属性名的对应-->
<!--        主键类型使用id标签-->
        <id column="id" property="cid" />
<!--        非主键类型使用result标签-->
        <result column="name" property="cname" />
<!--        列名和属性名相同不用定义-->
        <result column="email" property="email" />
        <result column="age" property="age" />
    </resultMap>

使用resultMap属性,指定映射关系的id

<select id="selectStudentById" resultMap="studentMap">
	select id,name,email,age from student where id=#{studentId}
</select>

resultMap和resultType不能同时使用,二选一

3.3.3 实体类属性名和列名不同的处理方式

(1)使用列别名和<resultType>

步骤:

1、创建新的实体类PrimaryStudent

package org.example.pojo;
/**
* <p>Description:实体类</p>
* <p>Company:http://www.tyx.com
*/
public class PrimaryStudent{
    private Integer stuId;
    private String stuName;
    private Integer stuAge;
    //set,get方法
}

2、接口方法

List<PrimaryStudent> selectUserFieldAlias(QueryParam param);

mapper文件

<!-- 使用列别名,解决列名和属性名不同的问题-->
<select id="selectById" resultType="org.example.mybatis.pojo.Student">
	select id stuId,name stuName,age stuAge from student where id=#{stuid}
</select>

(2)使用resultMap:自定义列名和属性名称对应关系

3.4 自定义别名

mybatis提供的对java类型定义简短、好记名称

自定义别名的步骤:

1)在mybatis主配置文件,使用typeAliase标签声明别名

2)在mapper文件中,resultType=“别名”

声明别名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cKQUyDGP-1642483473078)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210829161006841.png)]

放在settings语句的后面

<!--
	第一种语法格式
	type:java类型的全限定名称(自定义类型)
	alias:自定义别名
-->
<typeAliases>
    <typeAlias type="org.example.mybatits.pojo.Student" alias="stu"/>
</typeAliases>

mapper文件中使用

resultType=“别名"

优点:别名可以自定义

缺点:每个类型必须单独定义

<!-- 第二种方式
	name:包名,mybatis会把这个包中所有类名作为别名(不用区分大小写)
	优点:使用方便,一次给多个类定义别名
	缺点:别名不能自定义,必须是类名
-->
<package name="org.example.mybatis.pojo"/>

建议:不用别名

模糊

模糊查询的实现有两种方式,一是java代码中给查询数据加上”%“;二是在mapper文件sql语句的条件位置加上”%“

(推荐使用)第一种方式:在java程序中,把like的内容组装好,把这个内容传入到sql语句

dao方法

List<Student> selectLikeOne(@Param("name") String name);

mapper文件

<select id="selecLikeOne" resultMap="studentMap">
	select * from student where name like #{name}
</select>
String name = "%李%";

第二种方式:在sql语句中,组织like的内容

sql语句中like的格式:where name like “%“空格#{name}空格”%”

第四章 MyBatis框架动态SQL

动态SQL,通过MyBatis提供的各种标签对条件作出判断以实现动态拼接SQL语句。这里的条件判断使用的表达式为OGNL表达式。常用的动态SQL标签有<if>、<where>、<choose/>、<foreach>等

MyBatis的动态SQL语句,与JSTL的语句非常相似

什么是动态sql:同一个dao的方法,根据不同的条件可以表示不同的sql语句,主要是where部分有变化

使用mybatis提供的标签,实现动态sql的能力

使用动态sql时,dao方法的形参使用java对象

动态SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询,提交的查询条件不同,执行的SQL语句不同,若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的sql语句。此时,可使用动态sql来解决这样的问题

4.1 if

语法

<if test="boolean判断结果">
	sql代码
</if>

多个if可以同时存在,但没有else

mapper文件中
<select id="selectStudent" resultType="org.example.mybatits.pojo.Student">
	select * from student
    <if test="条件">
    	sql语句
    </if>
</select>

test:使用对象的属性值作为条件

<select id="selectIf" resultType="org.example.mybatits.pojo.Student">
    select * from student
    where
    <if test="name != null and name != ''">
    	name = #{name}
    </if>
    
    <if test="age > 0">
		or age &lt; #{age}    
    </if>
</select>

多条件查询时使用动态sql和实体

在mapper的动态SQL中若出现大于号(>)、小于号(<)、大于等于号(>=)、小于等于号(<=)等符号,最好将其转换为实体符号。否则,XML可能会出现解析出错问题

特别是对于小于号(<),在XML中是绝不能出现的,否则解析mapper文件会出错

实体符号表:

< 小于 &lt;
> 大于 &gt;
>= 大于等于 &get;=
<= 小于等于 &lt;=

4.2 where标签

使用if标签时,容易引起sql语句语法错误,使用where标签解决if产生的语法问题

使用时,先写where,里面时一个或多个if标签,当有一个if标签判断条件为true,where标签会转为WHERE关键字,附加到sql语句的后面。如果if没有一个条件为true,忽略where和里面的if

语法:
<where>
	<if test="条件1">sql语句1</if>
    <if test="条件2">sql语句2</if>
</where>
<select id="selectWhere" resultType="org.example.mybatits.pojo.Student">
	select * from student
    <where>
    	<if test="name != null and name !=''">
        	or name = #{name}
        </if>
        
        <if test="age>0">
        	or age &lt; #{age}
        </if>
    </where>
</select>

where标签删除和它最近的or或者and

4.3 foreach标签

<foreach/>标签用于实现对于数组与集合的遍历,对其使用,需要注意:

  • collection表示要遍历的集合类型,list,array等
  • open、close、separator为对遍历内容的SQL拼接、

使用foreach可以循环数组、list集合,一般使用在in语句中

语法:

<foreach collection="集合类型" open="开始的字符" close="结束的字符" item="集合中的成员" separator="集合成员之间的分隔符">
	#{item的值}
</foreach>

标签属性:

collection:表示循环的对象是数组还是list集合,如果dao接口方法的形参是数组,collection=”array“,如果dao接口形参是List,collection=”list“

open:循环开始的字符sql.append("(");

close:循环结束时字符sql.append(")");

item:集合的成员,自定义的变量 Integer item = idlist.get(i); //item是集合成员

separator:集合成员之间的分隔符sql.append(","); //集合成员之间的分隔符

#{item的值}:获取集合成员的值

(1)遍历List<简单类型>

表达式中的List使用list表示,其大小使用list.size表示

dao方法:

List<Student> selectForeachOne(List<Integer> idlist);

mapper文件:

<select id="selectForeachOne" resultType="org.example.mybatits.pojo.Student">
    select * from student 
	<if test="list != null and list.size()>0">
    	where id in
        <foreach collection="list" open="(" close=")" separator="," item="myid">
    		#{myid}
    	</foreach>
    </if>
</select>

(2)foreach对象类型的List

dao方法

List<Student> selectForeach(List<Student> studentList);

mapper文件

<select id="selectForeachOne" resultType="org.example.mybatits.pojo.Student">
    select * from student 
	<if test="list != null and list.size()>0">
    	where id in
        <foreach collection="list" open="(" close=")" separator="," item="stu">
    		#{stu.id}
    	</foreach>
    </if>
</select>

4.4 动态SQL之代码片段

<sql/>标签用于定义SQL片段,以便其它SQL标签复用,而其他标签使用该SQL片段,需要使用<include/>子标签,该<sql/>标签可以定义SQL语句中的任何部分,所以<include/>子标签可以放在动态SQL的任何位置

sql标签表示一段sql代码,可以是表名,几个字段,where条件都可以,可以在其他地方复用sql标签的内容

使用方式:

1)在mapper文件中定义sql代码片段<sql id="唯一字符串">部分sql语句</sql>

2)在其他的位置,使用include标签引用某个代码片段

接口方法:

List<Student> selectStudentSqlFragment(List<Student> stuList);

mapper文件:

<!--创建sql片段id:片段的自定义名称-->
<sql id="studentSql">
	select id,name,email,age from student
</sql>
<select id="selectForeachOne" resultType="org.example.mybatits.pojo.Student">
    <include refid="studentSql"/>
	<if test="list != null and list.size()>0">
    	where id in
        <foreach collection="list" open="(" close=")" separator="," item="stu">
    		#{stu.id}
    	</foreach>
    </if>
</select>
<sql id="studentFieldList">
	id,name,email
</sql>
<select id="selectForeachOne" resultType="org.example.mybatits.pojo.Student">
    select <include refid="selectFieldList"/> from student 
	<if test="list != null and list.size()>0">
    	where id in
        <foreach collection="list" open="(" close=")" separator="," item="stu">
    		#{stu.id}
    	</foreach>
    </if>
</select>

第五章 MyBatis配置文件

mybatis配置文件有两大类:1、mybatis主配置文件;2、mybatis的mapper文件

1、mybatis主配置文件,提供mybatis全局设置的,包含的内容:日志、数据源、mapper文件位置

2、mapper文件:写sql语句的,一个表一个mapper文件

5.1 settings部分

settings是mybatis的全局设置,影响整个mybatis的运行,这个设置一般使用默认值就可以了

官方文档

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sYTdbAk5-1642483473078)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830091713115.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V8W2C7JT-1642483473080)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830091810507.png)]

5.2 typeAliase别名

设置别名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ATmYWVM8-1642483473080)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830091920321.png)]

5.3 配置环境

environments:环境标签,在他里面可以配置多个environment

属性:default,必须是某个environment的id属性值,表示mybatis默认连接的数据库

environment:表示一个数据库的连接信息

属性:id自定义的环境的标识,唯一值

transactionManager:事务管理器

属性:type表示事务管理器的类型

属性值:1)JDBC:使用Connection对象,由mybatis自己完成事务的处理

2)MANAGED:管理,表示把事务的处理交给容器实现(由其他软件完成事务的提交,回滚)

datasource:数据源,创建的Connection对象,连接数据库

属性:type数据源的类型

属性值:1)POOLED,mybatis会在内存中创建PooledDataSource类,管理多个Connection连接对象,使用的连接池

2)UNPOOLED,不使用连接池,mybatis创建一个UnPooledDataSource这个类,每次执行sql语句先创建Connection对象,再执行sql语句,最后关闭Connection

3)JNDI:java的命名和目录服务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-71oDFmif-1642483473081)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830092041048.png)]

5.4 使用数据库属性配置文件

需要把数据库的配置信息放到一个单独文件中,独立管理,这个文件扩展名是properties,在这个文件中,使用自定义的key=value的格式表示数据

使用步骤:

1)在resource目录中,创建xxxx.properties

2)在文件中,使用key=value的格式定义数据

例如:jdbc.url=jdbc:mysql://localhost:3306/test

3)在mybatis主配置文件,使用<property>标签引用外部的属性配置文件

4)在使用值的位置,使用${key}获取key对应的value(等号右侧的值)

<configuration>
	<!-- 使用外部属性配置文件 -->
	<properties resource="jdbc.properties" />		使用类路径之下的属性文件

resource:指定类路径下的某个属性配置文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N9YYhvk4-1642483473081)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830100535348.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z96L0SMN-1642483473082)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830100634889.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J6hFs6Y1-1642483473082)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830100655455.png)]

5.5 mapper标签

使用mapper指定其他mapper文件的位置

mapper标签使用的格式有两个常用的方式

第一种方式:resource=“mapper文件的路径”

优点:文件清晰,加载的文件是明确的,文件的位置比较灵活

缺点:文件比较多,代码量会比较大,管理难度大

<mappers>
	<mapper resource="org/example/mybatis/dao/StudentDao.xml"/>
</mappers>

第二种方式:使用<package>

name:包名,mapper文件所在的包名

特点:把这个包中的所有mapper文件,一次加载

<package name="org.example.mybatis.dao"/>

使用要求:

1、mapper文件和dao接口在同一目录

2、mapper文件和dao接口名称完全一致

第六章 扩展

6.1 PageHelper

一个插件

6.1.1 MyBatis通用分页插件

https://github.com/pagehelper/Mybatis-PageHelper

(1)maven坐标获取

(2)加入plugin配置

在<environments>之前加入

<plugins>
	<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>

(3)PageHelper对象

查询语句之前调用PageHelper startPage静态方法

除了PageHelper startPage方法外,还提供了类似用法的PageHelper.offsetPage方法

在你需要进行分页的MyBatis查询方法前调用PageHelper.startPage静态方法即可,紧跟在这个方法后的第一个MyBatis查询方法会被进行分页

@Test
public void testTest() throws IOException {
    //获取第1页,3条内容
    PageHelper.startPage(1,3);
    List<Student> studentList = studentDao.selectStudents();
    studentList,forEach(stu -> System.out.println(stu));
}

PageHelper做数据分页,在你的select语句后面加入分页的sql内容,如果你使用的mysql数据库,它就是在select * from studetn后面加入limit语句

使用步骤:

1、加入依赖pageHelper依赖

<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.1</version>
</dependency>

2、在mybatis主配置文件,加入plugin声明

3、在select语句之前,调用PageHelper.startPage(页码,每页大小)

个常用的方式

第一种方式:resource=“mapper文件的路径”

优点:文件清晰,加载的文件是明确的,文件的位置比较灵活

缺点:文件比较多,代码量会比较大,管理难度大

<mappers>
	<mapper resource="org/example/mybatis/dao/StudentDao.xml"/>
</mappers>

第二种方式:使用<package>

name:包名,mapper文件所在的包名

特点:把这个包中的所有mapper文件,一次加载

<package name="org.example.mybatis.dao"/>

使用要求:

1、mapper文件和dao接口在同一目录

2、mapper文件和dao接口名称完全一致

第六章 扩展

6.1 PageHelper

一个插件

6.1.1 MyBatis通用分页插件

https://github.com/pagehelper/Mybatis-PageHelper

(1)maven坐标获取

(2)加入plugin配置

在<environments>之前加入

<plugins>
	<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>

(3)PageHelper对象

查询语句之前调用PageHelper startPage静态方法

除了PageHelper startPage方法外,还提供了类似用法的PageHelper.offsetPage方法

在你需要进行分页的MyBatis查询方法前调用PageHelper.startPage静态方法即可,紧跟在这个方法后的第一个MyBatis查询方法会被进行分页

@Test
public void testTest() throws IOException {
    //获取第1页,3条内容
    PageHelper.startPage(1,3);
    List<Student> studentList = studentDao.selectStudents();
    studentList,forEach(stu -> System.out.println(stu));
}

PageHelper做数据分页,在你的select语句后面加入分页的sql内容,如果你使用的mysql数据库,它就是在select * from studetn后面加入limit语句

使用步骤:

1、加入依赖pageHelper依赖

<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.1</version>
</dependency>

2、在mybatis主配置文件,加入plugin声明

3、在select语句之前,调用PageHelper.startPage(页码,每页大小)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-igblaRuw-1642483473083)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830104706119.png)]

上一篇:Synthetix创始人新作:募资,应以DAO当先


下一篇:【学习笔记】MyBatis学习笔记