Mybatis框架

1.什么是Mybatis

一种持久层的框架,类似于JDBC访问数据库的操作

jdbc使用的是Connection对象,PreparedStatement对象,ResultSet对象

而mybatis框架的核心对象有SqlSessionFactoryBuilder对象和SqlSessionFactory对象和SqlSession对象等,并且mybatis框架较为灵活

2.为什么使用框架:

通过框架来制定开发规范,更进一步保证所有的开发人员能够快速编写统一的代码,让开发人员专注于业务实现

3.常用框架技术

3.1 Spring

Spring是一个J2EE的框架,这个框架提供了对轻量级IOC的良好支持,同时也提供了对AOP技术非常好的封装,相比于其他的框架,Spring框架的设计更加模块化,框架内的每个模块都能完成特定的工作,而且各个模块可以独立的运行,不会相互的前置,因此,在使用Spring框架的时候,我们可以使用整个框架,也可以使用框架中的一部分

主要学习:

IOC:控制反转---DI(依赖注入),spring容器化管理,取代new对象

AOP:面向切面,专门的人做专门的事

3.2 SpringMVC

Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。

3.3 Mybatis

Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高

3.4Mybatis组成部分

核心对象:

SqlSessionFactoryBuilder; 用于生成SqlSessionFactory

SqlSessionFactory; 用于生成SqlSession

SqlSession; 用于执行sql语句

配置文件:

核心配置文件:mybatis-config.xml

sql映射文件:映射实体类和数据库中的表

4.mybatis小工程

4.1创建数据库:

CREATE TABLE `t_person` (
  `id` int(32) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `nickname` varchar(32) DEFAULT NULL,
  `age` int(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;


INSERT INTO `t_person` VALUES ('1', 'zs', 'zz', '3');
INSERT INTO `t_person` VALUES ('2', 'lisi', 'll', '4');
INSERT INTO `t_person` VALUES ('3', 'wangwu', 'ww', '5');

创建一个数据库

4.2创建一个maven工程

包的结构路径,在src下面创建一个test文件夹,里面创建一个java文件夹,(test和main同级)设置为test类型

main中,和webapp同级的创建两个文件夹,一个java,一个resources,java设置问java文件夹,resources为资源文件夹

然后再java文件夹中创建包结构,域名.组织域名.工程名.包名。例如:cn.kgc.mybatis.entity实体类包

4.3加入依赖:

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.1</version>
</dependency>
mybatis jar包依赖
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.36</version>
</dependency>
mysql 依赖
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

4.4修改工程环境:

某些环境不更改,可能不会出现问题,可能和自己的环境有关

 在pop.xml文件中将1.7修改成1.8

 在project Structure中修改

 在setting中搜索修改:

 4.5创建实体类

Person.java在cn.kgc.pro_mybatis.entity中

加载lombokjar包后,添加@Getter和@Setter就默认生成getset方法

@Getter
@Setter
public class Person {
    private Integer id;
    private String name;
    private String nickName;
    private Integer age;
}

4.6创建mapper/PersonMapper接口

mapper接口相当于dao接口,不同的是不需要手动写BaseDao工具类和实现类,mybatis框架中自动实现

package cn.kgc.pro_mybatis.mapper;

public interface PersonMapper {
    public Integer findCount();
}

4.7 创建mybatis映射文件resources.cn.kgc.mybatis.PersonMapper.xml

在resources中创建目录,和前面的尽量保持一致,保持一个相同的路径可以更容易理解

<?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="cn.kgc.pro_mybatis.mapper.PersonMapper"> 
<-- namespace,命名空间,是对应的mapper接口的包路径 -->
    <-- 里面添加sql语句,id是mapper接口中的方法名,不可以同名, -->
    <-- resultType是返回值类型的路径 -->
    <select id="findCount" resultType="java.lang.Integer">
        select count(*) from t_person 
         <-- sql语句 -->
    </select>
</mapper>

4.8 创建mybatis主配置文件mybatis-config.xml

在resources目录下,创建主配置文件,mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
        "http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
<-- 文件头 -->
<configuration>
    <-- 环境配置:数据库的连接信息 -->
    <-- default:配置的值需要和某个enviroment的id相同,访问对应的数据库 -->   
    <environments default="development">
        <environment id="development">
            <-- mybatis的事务类型,选择JDBC -->  
            <transactionManager type="JDBC"></transactionManager>
            <-- 数据源 --> 
            <dataSource type="POOLED">
            	<-- 四个属性 --> 
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/db_mybatis001"/>
                <property name="username" value="root"/>
                <property name="password" value="111"/>
            </dataSource>
        </environment>
    </environments>
    
    <mappers>
        <mapper resource="cn/kgc/pro_mybatis/mapper/PersonMapper.xml"/>
    </mappers>
</configuration>

注意下面的mappers中,路径是\,不是.

而且在创建路径的时候,是\

 用.创建会在mapper中添加resource后无法识别

4.9测试类TestMybatis.java

在test,java中创建一个测试类,利用三大对象进行测试

package cn.kgc.test;

import cn.kgc.entity.Person;
import cn.kgc.mapper.PersonMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

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

public class Test {
    @org.junit.Test
    public void testFindCount() throws IOException {
        //通过Resources.getResourceAsStream读取主配置文件,以流的形式
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        //实例化SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //通过实例化SqlSessionFactoryBuilder创建SqlSessionFactory
        SqlSessionFactory build = builder.build(in);
        //通过SqlSessionFactory对象的openSession方法创建SqlSession
        SqlSession sqlSession = build.openSession();
        //执行方法
        Integer count = sqlSession.getMapper(PersonMapper.class).findCount();
        System.out.println("count:" + count);
        //关闭流对象
        sqlSession.close();
    }
}

可以看到运行结果:

 总记录数:4

5.优化改进:

5.1加入日志配置:

在主配置文件中添加setting,添加日志信息

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

 此时再次执行:可以看到具体执行的日志文件

 这就是一个简单的mybatis的实现工程

5.2增删改等方法:

在上面测试了查询方法,现在可以试试增删改方法:

首先在mapper接口中添加方法,以增加为例子:

//增加
Integer addPerson(Person person);

sql映射文件:

注意:增删改查对应不同的标签,增删改没有返回值类型

<insert id="addPerson" parameterType="cn.kgc.mapper.PersonMapper">
    insert into t_person(`name`,nickname,age) values (#{name},#{nickname},#{age})
</insert>

 增insert,删delete,改update,查select

test测试:

注意:增删改需要先提交,commit(),先条件后关闭

@org.junit.Test
public void testAddPerson() throws IOException {
    InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory build = builder.build(in);
    SqlSession sqlSession = build.openSession();
    Person person = new Person();
    person.setName("yangchaoyue");
    person.setNickname("杨超越");
    person.setAge(22);
    sqlSession.getMapper(PersonMapper.class).addPerson(person);
    //提交事务
    sqlSession.commit();
    sqlSession.close();
}

5.3多参数要注意:

单个参数添加类型路径,多个参数建议封装

多个参数不封装的话加注解@Param("name"),在加入注解后,sql映射文件中就不需要添加参数类型

或者利用Map,用来存放数据

Person findByNameNickname(Person person);
Person findByNameNickname2(@Param("name") String name, @Param("nickname") String nickname);
Person findByNameNickname3(Map<String,Object> map);

对应的sql映射文件:

<select id="findByNameNickname" resultType="cn.kgc.entity.Person" parameterType="cn.kgc.entity.Person">
    select * from t_person where `name`=#{name} and nickname=#{nickname}
</select>

<select id="findByNameNickname2" resultType="cn.kgc.entity.Person">
    select * from t_person where `name`=#{name} and nickname=#{nickname}
</select>

<select id="findByNameNickname3" resultType="cn.kgc.entity.Person" parameterType="java.util.Map">
    select * from t_person where `name`=#{name} and nickname=#{nickname}
</select>

5.4优化测试类,添加工具类

在测试的时候,可以看到,每个测试方法,都需要三大对象来创建,所以将相同的代码片段提取,封装成一个工具类

package cn.kgc.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

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

public class MybatisUtil {
    //定义私有的静态SqlSessionFactory对象
    private static SqlSessionFactory factory = null;

    //在类加载的时候执行,读取配置文件,创建一个SqlSessionFactory对象并赋值
    static {
        try {
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            factory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取SqlSession
    public static SqlSession getSqlSession() {
        SqlSession sqlSession = null;
        if (factory != null) {
            sqlSession = factory.openSession();
        }
        return sqlSession;
    }
}

5.5sql语句中的#和$

在sql映射文件中,可以添加#或者$来进行值的操作

但是#是传递值

而$是替代字段

例如,在查询排序的时候,用两个不同的符号,会出现不同的效果,#无法排序

除此之外,#安全PreparedStatement,$不安全Statement

在不同的sql语句下查询的结果:

select * from t_person order by #{msg}
<==        Row: 1, diliraba, 迪丽热巴, 18
<==        Row: 2, yangmi, 杨幂, 19
<==        Row: 3, wuxuanyi, 吴宣仪, 20
<==        Row: 5, gulinazha, 古力娜扎, 17

select * from t_person order by ${msg}
<==        Row: 5, gulinazha, 古力娜扎, 17
<==        Row: 1, diliraba, 迪丽热巴, 18
<==        Row: 2, yangmi, 杨幂, 19
<==        Row: 3, wuxuanyi, 吴宣仪, 20

5.6将主配置文件的四个路径改成配置文件的方式:

将主配置文件中的死数据修改成活数据

在resources文件夹根目录下创建文件jdbc.properties,添加jdbc连接数据库的参数

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db_mybatis001
username=root
password=111

在主配置文件中添加资源路径,并修改下方的参数

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
        "http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
<configuration>
    <properties resource="jdbc.properties"/>
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <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="cn/kgc/mapper/PersonMapper.xml"/>
    </mappers>
</configuration>

6.mybatis映射:

resultType和resultMap

 

在sql映射文件中,我们需要对每个方法的id,参数,方法进行设置,其中返回值在某些情况下返回的值和实体类中的字段不同,在不给别名的情况下,resultType无法设置,此时需要用到resultMap

resultType :直接表示返回类型,用在简单场景 ,基本数据类型

resultMap :复杂数据类型时候,用对外部resultMap的引用

应用场景:

数据库字段信息与对象属性不一致

复杂的联合查询,自由控制映射结果

二者不能同时存在,本质上都是Map数据结构

使用:

 如图,t_user的rid是t_role的id,两张表关联查询,此时实体类User中的属性有

@Getter
@Setter
public class User {
    private Integer id;
    private String name;
    private String  password;
    private Integer rid;
    
    //t_role中的name,防止重名,修改名字
    private String roleName;
}

 在实体类中的名字为roleName对应的是b表中的name,此时有两种解决办法,

一个是修改sql语句,添加别名:

select a.id,a.name,a.password,b.name as roleName from t_user a,t_role b where a.rid=b.id and a.name=?;

此时就会一一对应,返回值类型用一个实体类接收,用resultType即可

1.实体类中有一条或少量基础数据类型

假如不使用别名可以用resultMap:

mapper接口:

//resultMap
User findResultMap(User user);

sql映射文件:

<select id="findResultMap" parameterType="cn.kgc.mybatis.entity.User" resultMap="resultMap">
    select a.id,a.name,a.password,b.name from t_user a,t_role b where a.rid=b.id
    and name = #{name}
</select>
<-- resultMap配置:前面property是实体类中的名字,后面column是数据库中的名字,给别名就不需要这个-->
<resultMap id="resultMap" type="cn.kgc.mybatis.entity.User">
    <result property="id" column="id"></result>
    <result property="name" column="name"></result>
    <result property="password" column="password"></result>
    <result property="roleName" column="name"></result>
</resultMap>

上面是最基础的resultMap:

2.实体类中有引用类型属性

当某次查询有多个别的类的属性的时候,一一添加多个属性或者多个别名会造成数据混乱,建议添加一个实体类(引用数据类型作为属性)

//将role表插入
private Role role;

mapper接口:

//利用user-role查询用户列表
List<User> findUserRole(Integer userRole);

sql映射文件:

<select id="findUserRole" parameterType="java.lang.Integer" resultMap="userRoleMap">
    select a.id,a.userCode,b.roleName from smbms_user a,smbms_role b where a.userRole=b.id and a.userRole=#{userRole}
</select>
<resultMap id="userRoleMap" type="cn.kgc.mybatis003.entity.User">
    <-- type是User路径,User中有Role role -->
    <-- id是主键的意思,用result也可以,前面的字段都是第一张表的属性 -->
    <id property="id" column="id"></id>
    <result property="userCode" column="userCode"></result>
    <-- association是其中的别的表的字段,type是那张表的路径,property是User属性中的Role的名字 -->
    <association property="role" javaType="cn.kgc.mybatis003.entity.Role">
        <result property="roleName" column="roleName"></result>
    </association>
</resultMap>

3.实体类中有引用数据类型的集合

User实体类添加别的表的实体类,一对多,集合展示

private List<Address> addressList;

mapper接口:

//Collection查询
List<User> findCollection(@Param("id") Integer id);

sql:

<select id="findCollection" resultMap="collectionMap">
    select a.id,a.userCode,b.addressDesc from smbms_user a,smbms_address b where a.id=b.userId and a.id=#{id}
</select>
<resultMap id="collectionMap" type="cn.kgc.mybatis003.entity.User">
    <id property="id" column="id"></id>
    <result property="userCode" column="userCode"></result>
    <collection property="addressList" ofType="cn.kgc.mybatis003.entity.Address">
        <result property="addressDesc" column="addressDesc"></result>
    </collection>
</resultMap>

7.Mybatis动态sql

mybatis前面的查询语句都是定死的,但是当模糊查询的时候,某些字段可能有,可能没有,所以就要添加语句,让sql变成动态

7.1查询(if判断条件)

mapper接口:多字段模糊查询,实现输入不输入都能查询

//多字段模糊查询
List<User> findByNamePwd(@Param("name") String name, @Param("password") String password);

sql映射文件:

中间添加if,test中是判断条件,成功则拼接

<select id="findByNamePwd" resultType="cn.kgc.mybatis003.entity.User">
    select * from smbms_user where 1 = 1
    <if test="name!=null and name!=''">
        and userName like concat("%",#{name},"%")
    </if>
    <if test="password!=null and password!=''">
        and userPassword = #{password}
    </if>
</select>

7.2 增加(trim去除最后的,)

//动态添加
Integer addDongTai(User user);

sql映射文件:

同样if判断,在if判断外面添加trim去除最后的,

<insert id="addDongTai" parameterType="cn.kgc.mybatis003.entity.User">
    insert into smbms_user(
    <trim suffixOverrides=",">
        <if test="userCode != null and userCode != ''">
            userCode,
        </if>
        <if test="userName != null and userName != ''">
            userName,
        </if>
    </trim>
    ) values(
    <trim suffixOverrides=",">
        <if test="userCode != null and userCode != ''">
            #{userCode},
        </if>
        <if test="userName != null and userName != ''">
            #{userName},
        </if>
    </trim>
    )
</insert>

当有userCode,没有userName的时候,sql语句就变成:

insert into smbms_user(userCode) values(#{userCode})

3.修改(trim中的别的属性)

//动态修改
Integer updateUserNew(User user);

suffixOverrides后缀覆盖

suffix后缀添加

prefix前缀添加

不同的属性都是为了拼接sql语句

<update id="updateUserNew" >
    update smbms_user
    <trim suffixOverrides="," suffix="where id=#{id}" prefix="set">
        <if test="userCode != null and userCode != ''">
            userCode=#{userCode},
        </if>
        <if test="userName != null and userName != ''">
            userName=#{userName},
        </if>
    </trim>
</update>

7.4参数是列表:(foreach)

当参数是一个列表的时候:

//动态参数为list查询
List<User> findByList(List<BigInteger> id);

sql映射文件:

collection是list,代表类型

open是开头

close是结尾

item参数,是传入的值

separator是间隔符号

<select id="findByList" resultType="cn.kgc.mybatis003.entity.User">
    select * from smbms_user where id in
    <foreach collection="list" open="(" close=")" item="id" separator=",">
        #{id}
    </foreach>
</select>

7.5,当参数是一个map<String,Object>,其中Object是一个列表类型的时候

//动态参数为map查询
List<User> findByMap(Map<String , Object> map);

和list的类似,但是collection不同,相当于key

<select id="findByMap" resultType="cn.kgc.mybatis003.entity.User">
    select * from smbms_user where id in
    <foreach collection="ids" open="(" close=")" item="map" separator=",">
        #{map}
    </foreach>
    and userPassword in
    <foreach collection="userPassword" open="(" close=")" item="map" separator=",">
        #{map}
    </foreach>
</select>

测试类:

@org.junit.Test
public void testFindByMap() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    List<Integer> list = new ArrayList<>();
    list.add(16);
    list.add(17);
    List<Integer> list1 = new ArrayList<>();
    list1.add(123);
    list1.add(123456);
    HashMap<String, Object> hashMap = new HashMap<>();
    hashMap.put("ids",list);
    hashMap.put("userPassword",list1);
    List<User> users = sqlSession.getMapper(UserMapper.class).findByMap(hashMap);
    for (User user:users){
        System.out.println(user.getUserName());
    }
    sqlSession.close();
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值