Mybatis

POJO

(Plain Old Java Objects,普通老式 Java 对象)

package com.jt.springboot_demo2.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;

/**
 * 实体对象:
 * 1、类名与表名对应
 * 2、属性与字段对应
 * 3、pojo属性必须包装类型
 *      0与null可区分是否赋值
 * 4、实体对象必须有get/set方法
 * 5、一般实体对象必须实现序列化接口(规则)
 *      原因:数据可能跨平台(跨服务器)传输
 * */

@Data   //动态生成get/set/toString/equal
@Accessors(chain=true)      //重写set方法,实现链式赋值
@NoArgsConstructor      //无参构造
@AllArgsConstructor     //全参构造
public class DemoUser implements Serializable {
    private Integer id;
    private String name;
    private Integer age;
    private String sex;

    //this在运行期有效,代表当前对象     链式加载
    public DemoUser setId(Integer id){
        this.id = id;
        return this ;
    }


    public void add(){
        DemoUser d = new DemoUser();
        d
                .setAge(21)
                .setId(12)
                .setName("xy")
                .setSex("man");
    }
}

MyBatis

持久化:将内存数据保存到磁盘中

持久层:程序通过Dao(Data Access Objects)/Mapper层与数据库进行交互的层级

小结:基于ORM设计实现以对象的方式操作数据库

tips:resources文件下创建多层目录 cn/tedu/mapper

文件关系:

测试类 --加载–> 主配置文件 --sqlsession得到–> mapper接口 --导入接口方法–> mapper实例(执行sql)

主配置文件

mybatis-config.xml配置文件 路径:mybatis/mybatis-config.xml

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

    <!--环境配置标签,default默认环境-->
    <environments default="development">

        <!--编辑开发环境-->
        <environment id="development">
            <!--事务管理器-->
            <transactionManager type="JDBC"/>
            <!--mybatis采用数据库连接池的方式整合数据源-->
            <dataSource type="POOLED">		<!--使用池-->
                <!--高版本数据库添加cj-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&amp;useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;allowMultiQueries=true"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>

    </environments>

    <!--Mybatis加载Mapper映射文件-->
    <mappers>
        <mapper resource="mybatis/mappers/UserMapper.xml"/>
    </mappers>
</configuration>

测试类

public class TestMybatis {

    @Test
    public void demo1() throws IOException {
        //读取核心配置文件
        //指定配置文件地址
        String resource = "mybatis/mybatis-config.xml";
        //通过io流,加载指定的配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);

        //动态生成SqlSessionFactory
        SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(inputStream);


        //获取sqlsession,类比JDBC链接,执行sql语句最小单位
        SqlSession ss = ssf.openSession();
        //获取mapper接口,使用接口调用demoUserMapper.xml执行sql(底层JDBC执行sql)
        DemoUserMapper m = ss.getMapper(DemoUserMapper.class);
        //封装对象,返回结果集
        List<DemoUser> userList = m.findAll();

        System.out.println(userList);

        ss.close();
    }

    
//封装    
    SqlSessionFactory ssf;
    
    @BeforeEach		//@BeforeEach在@Test执行之前执行
    public void init() throws IOException {
        InputStream s = Resources.getResourceAsStream("mybatis/mybatis-config.xml");
        ssf = new SqlSessionFactoryBuilder().build(s);
    }

    @Test
    public void testFindByName(){
        //SqlSession sqlSession1 = ssf.openSession(true);
        SqlSession sqlSession= ssf.openSession();
        DemoUserMapper mapper = sqlSession.getMapper(DemoUserMapper.class);
        String s = "王昭君";
        List<DemoUser>  userList= mapper.findByName(s);
        System.out.println(userList);
        sqlSession.close();
    }
    
        @Test
    public void testSaveUser(){
        SqlSession sqlSession= ssf.openSession();
        DemoUserMapper mapper = sqlSession.getMapper(DemoUserMapper.class);
        DemoUser user = new DemoUser(null,"xy",12,"男");
        int rows = mapper.saveUser(user);	//方法做"更新"操作默认返回修改行数
        if(rows>0){
            System.out.println("影响行数"+rows);
            sqlSession.commit();
        }
        sqlSession.close();	//更新操作时,需要手动提交事务
    }
}

实体对象

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class DemoUser implements Serializable {
    private Integer id;
    private String name;
    private Integer age;
    private String sex;
}

mapper接口

mapper持久层下的DemoUserMapper接口

/*
* mybatis中的实现类以xml文件形式存在
* */
public interface DemoUserMapper {

    public List<DemoUser> findAll();	//在测试类中调用,在xml中实现

    DemoUser findOne(int id);
}

mapper实例

demoUserMapper.xml实例 路径:mybatis/mappers/demoUserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace是mybaits映射文件的唯一标识,与接口对应-->
<mapper namespace="com.jt.mapper.DemoUserMapper">
    
    <!--id 表示接口方法 resultType、parameterType如果是对象,则用该d包路径-->
    <select id="findAll" resultType="com.jt.pojo.DemoUser">
        select * from demo_user
    </select>

    <!-- parameterType可省略-->
    <select id="findOne" parameterType="int" resultType="com.jt.pojo.DemoUser">
        <!--通过#{}获取参数-->
        select * from demo_user where id = #{id}
    </select>

    <!--传递的是对象,可用属性直接使用-->
    <select id="findBySA" resultType="com.jt.springboot_demo3_mybatis.pojo.DemoUser">
        select * from demo_user where sex = #{sex} and age > #{age}
    </select>
    
    <!--执行跟新操作时,返回影响行数-->
    <insert id="saveUser">
        insert into demo_user value (null,#{name},#{age},#{sex})
    </insert>   
    
</mapper>

环境

环境:pom.xml导入jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
	<!--表示maven坐标-->
	<!-- 项目的组ID-->
    <groupId>com.jt</groupId>
	<!-- 项目名-->
    <artifactId>springboot_demo1</artifactId>
	<!--项目版本号-->
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot_demo1</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.4.1</spring-boot.version>
    </properties>

    <dependencies>

        <!--springboot的启动项  web相当于引入mvc框架
        思想:开箱即用,只需要引入jar包,简单配置即可使用该功能
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--引入单元测试的api-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--mybatis依赖包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>

        <!--jdbc依赖包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--支持热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <!--lombok依赖包-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>		 <!--父级标识-->
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <mainClass>com.jt.springboot_demo3_mybatis.SpringbootDemo3MybatisApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

多值传递

Mybatis默认支持单值传参,多值要转换为单值

Mybatis多值传参默认采用下标方式获取数据,应封装

封装策略:

1、封装为实体对象,属性只出现一次(只能传一个对象)

2、常用Map集合 Map<String,Object>

3、注解@Param(“key”) Object value (底层封装为Map)

相同类型的数据多值传递

1、array

2、List

3、Map

//测试类传入数组参数
int[] ids = new int[]{1,3,4,5};
int  rows = mapper.deleteIds(ids);

//传入List,只需要改collection参数
List list = new ArrayList();
int  rows = mapper.deleteList(list);

//传入map,只需要改collection参数
Map map = new HashMap();
map.put("ids",List);
int  rows = mapper.deleteM(map);  

集合遍历foreach

    <!--	collection:    	参数是数组,collection="array"    	list集合,collection="list"    	map集合,collection = "map中的kay"        item:每次遍历的形参变量,与#{}中的参数名一致        open:循环开始标签        close:循环结束标签        index:循环遍历下标(一般不用)        separator:循环遍历的分隔符    -->    <delete id="deleteIds">        delete form demo_user where id in         <foreach collection="array" item="id" open="(" close=")" separator=",">            #{id}        </foreach>    </delete>

map批量更新

    public void testUpdate1(){        SqlSession sqlSession = ssf.openSession(true);        DemoUserMapper mapper = sqlSession.getMapper(DemoUserMapper.class);        Map<String,Object> map = new HashMap<>();        String[] arr = {"小乔","大乔","王昭君"};        map.put("names", arr);        map.put("age", 18);        map.put("sex", "女");        mapper.updateUser(map);        sqlSession.close();    }
    <update id="updateUser">        update demo_user set age = #{age},sex = #{sex}        where name in (        <foreach collection="names" item="name" separator=",">            #{name}        </foreach>        )    </update>

注意事项

#号与$符的区别

对象或map集合传入参数可#{}直接使用

  • #{}以数据为参数,默认有预编译的效果,默认加了" " ,防止sql注入攻击

  • ${}以字段名称为参数,直接传值,慎用(写死,不传参数)

转义字符
&gt;	>大于&lt;	<小于&amp;	&与

转义标签体

<![CDATA[ sql语句 ]]>
 <![CDATA[select * from demo_user where age > #{minage} and age < #{maxage}]]>
SQL

大小写转换快捷键:ctrl+shift+u

like模糊查询

select * from demo_user where name like "%"#{s}"%"

Mybatis优化设置

配置pojo类别名

简化resultType的值

<!--主配置文件,配置别名--><typeAliases>    <!--只对某个类有效-->    <typeAlias type="cn.jt.pojo.DemoUser" alias="DemoUser"></typeAlias>    <!--自动拼接包名-->    <package name="cn.jt.pojo"/></typeAliases>
  	<!--mapper文件,拼接:cn.jt.pojo+DemoUser-->	<select id="select02" resultType="DemoUser">        SELECT * FROM DEMO_USER WHERE NAME LIKE "%"#{S}"%" ORDER BY AGE DESC    </select>

SQL标签

优势:缩减xml文件大小,代码结构相对简单

弊端:只能抽取公共部分,代码可读性差

    <sql id="demo_user_sql">        select * from demo_user    </sql>    <select id="select02" resultType="DemoUser">        <include refid="demo_user_sql"/>where name like "%"#{s}"%" order by age desc    </select>

Mybatis-动态SQL

where、if标签:去除多余and/or

    <select id="findWhere" resultType="DemoUser">        select * from demo_user        <where>            <if test="name != null">name = #{name}</if>            <if test="age != null">and age = #{age}</if>            <if test="sex != null">and sex = #{sex}</if>        </where>    </select>

set标签、if标签:去除多余逗号

    <update id="updateSet">        update demo_user            <set>                <if test="name != null">name = #{name},</if>                <if test="age != null">and age = #{age},</if>                <if test="sex != null">and sex = #{sex}</if>            </set>            where                id = #{id}    </update>

choose、when、otherwise标签

不想把全部条件当作if的判断(if-else),只执行一个条件

    <select id="choose" resultType="DemoUser">        select * from demo_user        where        <choose>            <when test="name != null">name = #{name}</when>            <otherwise>sex = #{sex}</otherwise>        </choose>    </select>

配置别名

    <!--配置别名,主配置文件顺序不可随便修改,在environment前-->    <typeAliases>        <!--只对某个类有效,别名标签-->        <typeAlias type="cn.jt.pojo.DemoUser" alias="DemoUser"></typeAlias>        <!--自动拼接包名,别名包-->        <package name="cn.jt.pojo"/>    </typeAliases>
@Alias("DemoUser")public class DemoUser implements Serializable {    private Integer id;    private String name;    private Integer age;    private String sex;}

resultType与resultMap

resultType:单表查询时字段与属性名一致

resultMap:解决字段(结果集)与属性名称不一致的问题

    <!--resultType:当结果集中字段名称与pojo中的属性一致时,才能实现自动封装-->    <select id="findAll" resultType="Dept">        select * from dept    </select>
 <select id="findAll" resultMap="deptRM">        select * from dept   </select>    <!--type简写了配置的包-->    <!--    自定义映射关系        id代表主键(每张表都有一个主键)            1.column代表 结果集 中的字段(结果集可用别名,如多表查询)            2.property代表封装的对象中的属性        result代表主键外的数据        -->    <resultMap id="deptRM" type="Dept">        <id column="dept_id" property="deptId"></id>        <result column="dept_name" property="deptName"></result>    </resultMap>

*Mybatis关联关系(多表查询)

关联查询效率高于子查询

一对一

关联查询:sql复杂,封装简单

    <select id="findAll" resultMap="empRM">        select * from emp left join  dept on dept.`dept_id`=emp.`dept_id`    </select>    <!--字段属性一致可以省略不写,最好保留主键        遇到关联封装,必须全部配置映射关系        autoMapping="true"实现自动映射;条件:多表查询,字段属性一致    --> 	<!--resultType返回值类型,select里引用resultMap里的type,为返回值类型-->    <resultMap id="empRM" type="Emp" autoMapping="true">        <id column="id" property="id"></id>        <!--完成一个对象属性的封装        	单个对象用association        	javaType指定属性类型,路径			固定搭配:association、javaType        -->       <!--association类比resultMap			没有column,改为对象,以下像resultMap一样建立映射关系            property为emp属性,将该属性封装为对象            javaType是封装对象的类型        -->         <association property="dept" javaType="cn.jt.pojo.Dept">            <id column="dept_id" property="deptId"></id>            <result column="dept_name" property="deptName"></result>        </association>    </resultMap>

子查询:sql简单,封装复杂

<!--where条件子查询-->    <select id="findAllWHere" resultMap="empRM2">        select * from emp    </select>    <resultMap id="empRM2" type="Emp" autoMapping="true">        <id column="id" property="id"></id>        <!--        column表示子查询的字段信息        select="sql的id"根据column中的数据实现子查询,		property="dept"		dept是在emp中的属性		column="dept_id"	dept_id把两个表的关联起来的字段			将emp中查到的dept_id作为根据,把dept中的dept_id连接,封装为对象,给emp        -->        <association property="dept" javaType="Dept"                     column="dept_id" select="findDept"></association>    </resultMap><!--子查询-->    <select id="findDept" resultMap="deptRM">        select * from dept where dept_id = #{dept_id}    </select>    <resultMap id="deptRM" type="Dept">        <id column="dept_id" property="deptId"></id>        <result column="dept_name" property="deptName"></result>    </resultMap>

一对多

关联查询

1、

<!--一对多-->    <select id="findDept" resultMap="listRM">        select d.dept_id,d.dept_name,e.id,e.name,e.age         from dept d         left join emp e on d.`dept_id`=e.`dept_id`    </select>    <resultMap id="listRM" type="Dept">        <id column="dept_id" property="deptId"></id>        <result column="dept_name" property="deptName"></result>        <!--ofType:封装list集合的泛型对象			ofType的类型是被封装的对象的类型-->        <collection property="emps" ofType="cn.jt.pojo.Emp" autoMapping="true">            <id column="id" property="id"></id>        </collection>    </resultMap>

2、

public class Rights extends BasePojo{    private Integer id;    private String name;    private Integer parentId;    private String path;    private Integer level;    private List<Rights> children; //不是表格固有属性,一对多:使用list集合}
    <!--不出现重名字段,进行重命名  resultMap多表查询-->	<select id="getRightsList" resultMap="rightsRM">        SELECT p.id,p.name,p.parent_id,p.path,p.level,p.created,p.updated,            c.id c_id,c.name c_name,c.parent_id c_parent_id,            c.path c_path,c.level c_level,c.created c_created,            c.updated c_updated            FROM            (SELECT * FROM rights WHERE parent_id=0)p	        LEFT JOIN	        rights c	        ON p.id = c.parent_id    </select>	<!--对对象Rights与数据库查询字段进行映射、封装-->    <resultMap id="rightsRM" type="Rights" autoMapping="true">        <id property="id" column="id"></id>        <!--对属性children与数据库查询数据进行映射-->        <collection property="children" ofType="Rights">            <id property="id" column="c_id"></id>            <result property="name" column="c_name"/>            <result property="parentId" column="c_parent_id"/>            <result property="path" column="c_path"/>            <result property="level" column="c_level"/>            <result property="created" column="c_created"/>            <result property="updated" column="c_updated"/>        </collection>

子查询

    <!--子查询-->    <select id="getRightsList2" resultMap="childrenRM">        SELECT * FROM rights WHERE parent_id=0    </select>        <resultMap id="childrenRM" type="Rights" autoMapping="true">        <id property="id" column="id"></id>        <!--column传给子查询的数据-->        <collection property="children" ofType="Rights" select="selectRightsByParentId" column="id"></collection>    </resultMap>        <!--单表查询子数据-->    <select id="selectRightsByParentId" resultType="Rights">        SELECT * FROM rights WHERE parent_id=#{id}    </select>

驼峰自动映射

关联查询生效需要开启:autoMapping=“true”

最后保留主键:,为以后拓展

<configuration>	<!--mybatis的核心配置-->    <settings>        <!--开启驼峰自动映射规则-->        <setting name="mapUnderscoreToCamelCase " value="true"/>    </settings><configuration>

Mybatis的缓存机制

降低访问物理设备次数,提高用户响应速度

一级缓存

默认开启,可以在同一个SqlSession对象中,查询相同数据,实现数据共享

规则:同一个SqlSession内部有效

二级缓存

默认开启,需要手动标识

规则:同一个SqlSessionFactory内部有效

在mapper实现类的xml文件中添加

<!--namespace是mybaits映射文件的唯一标识,与接口对应--><mapper namespace="cn.jt.mapper.DeptMapper">        <cache/>

说明:sqlSession查数据后交给一级缓存

​ sqlSession业务逻辑执行成功并且关闭

​ 二级缓冲才能起作用

增删改会删除一二级缓存

总结

ORM(Object Relational Mapping)对象关系映射

Mybatis是一个优秀的持久层框架,将接口和 Java 的 POJO映射成数据库中的记录。

补充

参数

mybatis利用下标取值,一个参数时,名称任意 #{任意} 但注意开发规范

map或@Param必须用key取值value #{key}

对象传参 #{属性}

动态代理

JDK动态代理

代理者必须实现接口,代理对象是目标对象的实现类或兄弟元素

CGLIB代理

不管是否实现接口接口,代理对象是目标对象的子类

spring自动导入jar包

mapper接口的说明

DemoUserMapper mapper = sqlSession.getMapper(DemoUserMapper.class);

接口不可创建对象,mapper为JDK动态代理对象

调用代理对象与接口功能一致

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值