MyBatis学习笔记——pzistart

1、MyBatis配置文件

<?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>
    
    <properties resource="db.properties"></properties>
    
     <typeAliases>
        <!--<typeAlias alias="user" type="com.kuang.bean.User"></typeAlias>-->
        <package name="com.kuang.bean"></package>
    </typeAliases>
    
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="1114"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/kuang/dao/UserMapper.xml"/>
    </mappers>
</configuration>

1.1 标签

  • 表示使用数据库连接

  • <properties resource="db.properties"></properties>  表示引入外部的配置文件
    
  • <typeAliases>
        <!--<typeAlias alias="user" type="com.kuang.bean.User"></typeAlias>-->
        <package name="com.kuang.bean"></package>
    </typeAliases>
        表示该类可以使用别名
    
  • mappers

    作用:扫包,为mapper接口创建实现类

    方式一

    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
    

    可以将mapper.xml放在dao或者resource包下

    方式二

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

    <mappers>
        <mapper class="com.kuang.dao.UserMapper"></mapper>
    </mappers>
    

    dao的命名要和mapper.xml的命名一致,并且放到一个包下面

    方式三

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

    <mappers>
        <package name="com.kuang.dao"></package>
    </mappers>
    

    dao的命名要和mapper.xml的命名一致,并且放到一个包下面

1.2 mapper.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">
<mapper namespace="com.kuang.dao.DeptMapper">
    
</mapper>

1.3 添加日志设置

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

1.4 dataBase

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=1114

2、生命周期作用域

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

  • SqlSessionFactoryBuilder 创建完了SqlSessionFactory就失去作用,所以它作为一个局部变量即可
  • SqlSessionFactory 可以被看做一个数据库连接池,作用是创建SqlSession,要长期保存它,但是不能存在多个Factory,单个便于对资源的管控,所以它最好作为单例模式
  • SqlSession 就相当于一个数据库连接,执行CRUD,事务的提交或回顾,所以它的作用域是一个方法中

3、resultMap

  • 在bean中的属性名和表中的列名不一致的时候使用
//id:表示对哪个resultMap作映射 type:表示返回值类型,可以从其中拿到属性
    <resultMap id="UserMap" type="User">
        <id column="id" property="id"></id>
        <result column="name" property="name"></result>
        <result column="pwd" property="password"></result>
    </resultMap>
        
<select id="getUserById" resultMap="UserMap">
    SELECT * from user where id = #{id}
</select>

标签

​ id:是该resultMap的一个标志,可以被其他resultMap使用

​ type:表示返回类型

​ id:表示这是主键列,会有特殊的封装规则

​ result:表示这是普通列

​ column:对应表中的列名

​ property:表示javaBean中对应的属性名

说明:id 和 column就是表中列名或者列的别名

3.1 外键

  • 特点:一致性,完整性
  • 两个表:A:学生(学号,姓名) B:学生成绩(学号,成绩);将表A的学号作为表B的外键
  • 想要在表B中插入某个学号的成绩,那么在表A中必须要有该学号;此时数据库对插入的数据做了关系检查
  • 想要删除表A中某个学生记录,必须确保表B中没有引用表A中的字段(学号);此时数据库对插入的数据做了关系检查
CREATE TABLE tbl_student(
id INT(10) PRIMARY KEY,
NAME VARCHAR(20)
);

CREATE TABLE tbl_stu_score(
math VARCHAR(10),
english VARCHAR(10),
stu_id INT(10),
CONSTRAINT fk_stu_score FOREIGN KEY(stu_id) 
REFERENCES tbl_student(id)
);

INSERT INTO tbl_student VALUES(1,"张三"),
(0002,"李四");

INSERT INTO tbl_stu_score VALUES
(100,100,1),
(99,99,2)

INSERT INTO tbl_stu_score VALUES(98,98,3)
#报错,因为没有0003这个学号

DELETE FROM tbl_student WHERE id = 1
#报错,无法删除,因为学生成绩表中引用了学生表中的id字段

#正确的删除方式
#首先删除成绩表
DELETE FROM tbl_stu_score WHERE stu_id = 1
#再删除学生表
DELETE FROM tbl_student WHERE id = 1
3.1.2 给已有的列添加外键
ALTER TABLE tbl_emp add CONSTRAINT emp_dept_fk FOREIGN KEY (d_id)
  REFERENCES tbl_dept(dept_id)
ALTER TABLE 子表 ADD CONSTRAINT 外键名 FOREIGN KEY (关联字段) 
REFERENCES 主表(被关联的字段) on delete cascade on update restrict;

3.2连接查询

3.2.1 把列值直接封装到bean中
    <resultMap id="getDifEmp" type="Employee">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>
        <result column="d_id" property="dept.id"></result>
        <result column="dept_name" property="dept.deptName"></result>
    </resultMap>

    <!--public Employee getEmployeeById(Integer id);-->
    <select id="getEmployeeById" resultMap="getDifEmp">
        SELECT e.`id`, e.`last_name`, e.`gender`, e.`email`, e.`d_id`,
          d.`dept_name`
        FROM tbl_employee e
        INNER JOIN tbl_dept d ON e.`d_id` = d.`id`
        WHERE e.id = #{id}
    </select>
3.2.2 association联合查询(1v1)
  • 在javaBean中含有一个bean对象的属性的时候封装使用
    <resultMap id="getDifEmp2" type="Employee">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>
        <association property="dept" javaType="Dept">
            <id column="id" property="id"></id>
            <result column="dept_name" property="deptName"></result>
        </association>
    </resultMap>
  • 标签

​ association:表示该bean中有联合了一个bean类型的属性,现在要自定义封装该联合对象

​ property:javaBean中联合的那个属性的属性名

​ javaType:该bean对应的类型

注意:我们使用联合查询的时候,要注意sql语句,同时要把联合的那个bean对象所在表的数据查询出来,这样才能有数据且成功赋值到这个bean所在的属性

<select id="queryAllEmps" resultMap="EmpAndDeptLimit">
  SELECT e.emp_id,e.emp_name,e.gender,e.email,d.dept_id,d.dept_name
    FROM tbl_emp e
    LEFT JOIN tbl_dept d ON e.d_id = d.dept_id
</select>
3.2.3 association分步查询(1v1)
  • 就是先查出表1,由于表1含有外键,这个外键来自表2;所以表2可以根据该外键查询出来
  • 最后封装起来返回一个对象

要查询出Emp对象

Emp中含有d_id,它来自于Dept中;

第一步查询出Emp的信息,不管是否要查询出d_id来封装,都会查询到d_id;

第二步根据d_id来查询出对应的Dept对象;最后封装成一个Emp对象返回

    <resultMap id="getStepEmp" type="Employee">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>
        //第二步查询
        <association property="dept" select="com.kuang.dao.DeptMapper.getDeptById" column="d_id"></association>
    </resultMap>

        //第一步查询
    <!--    public Employee getEmpByStep(Integer id);-->
    <select id="getEmpByStep" resultMap="getStepEmp">
        SELECT * from tbl_employee where id = #{id}
    </select>
  • 标签

​ property:表示联合的bean对象

​ select:当前property是调用select中指定的方法查询出来的

​ column:表示要将第一次查询出的哪个属性值传递到第二次select中的sql参数中

分步中的延迟加载
  • 配置以下两个属性,那么数据库查询出的结果就会按需加载,可以是数据库查询更优化
    <settings>
        <setting name="lazyLoadingEnabled" value="true"></setting>
        <setting name="aggressiveLazyLoading" value="false"></setting>
    </settings>

举例

    @Test
    public void testStep(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee emp = mapper.getEmpByStep(6);
        System.out.println(emp.getLastName());
        sqlSession.close();
    }

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

  • 可以看到只发送了一次sql语句,根据查询需求,数据库没有去查询dept属性
3.3.4 collection(1v多)
  • 在javaBean的属性中含有Collection(List、Set)类型的时候封装使用

查询一个部门中所有的Emps

	<resultMap id="getList" type="Dept">
        <id column="id" property="id"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps" ofType="Employee">
            <id column="id" property="id"></id>
            <result column="last_name" property="lastName"></result>
            <result column="gender" property="gender"></result>
            <result column="email" property="email"></result>
        </collection>
    </resultMap>

    <!--public Dept getDeptAndListById(Integer id);-->
    <select id="getDeptAndListById" resultMap="getList">
        SELECT d.`id`, d.`dept_name` ,
            e.`id`, e.`last_name`, e.`gender`, e.`email`
        FROM tbl_dept d
        LEFT JOIN tbl_employee e ON d.`id` = e.`d_id`
        WHERE d.`id` = #{id}
    </select>
  • 标签

collection:表示联合的属性是一个集合

property:表示联合的属性名

ofType:表示联合的属性的类型

3.3.5 collection分步查询
	<resultMap id="getListStep" type="Dept">
        <id column="id" property="id"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps" select="com.kuang.dao.EmployeeMapper.getEmployeeBydid" column="id"></collection>
    </resultMap>

    <!--public Dept getDeptAndListByStep(Integer id);-->
    <select id="getDeptAndListByStep" resultMap="getListStep">
        select * from tbl_dept where id = #{id};
    </select>
  • 同association的标签解释
3.3.6 分步查询的多值传递
    <resultMap id="getListStep" type="Dept">
        <id column="id" property="id"></id>
        <result column="dept_name" property="deptName"></result>
        <!--public List<Employee> getEmployeeBydid(Integer did);-->
        <collection property="emps"
                    select="com.kuang.dao.EmployeeMapper.getEmployeeBydid"
                    column="{did = id}"></collection>
    </resultMap>

    <!--public Dept getDeptAndListByStep(Integer id);-->
    <select id="getDeptAndListByStep" resultMap="getListStep">
        select * from tbl_dept where id = #{id};
    </select>
  • select中调用的方法,传参的时候使用 column="{key1 = value1, key2 = value2}" 的方式
3.3.7鉴别器
  • 用在sql语句中写判断
<resultMap id="getEmpDisc" type="Employee">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>

        <discriminator javaType="string" column="gender">
            <!--如果是女生-->
            <case value="0" resultType="com.kuang.bean.Employee">
                <association property="dept"
                             select="com.kuang.dao.DeptMapper.getDeptById"
                             column="d_id"></association>
            </case>
            <!--如果是男生-->
            <case value="1" resultType="com.kuang.bean.Employee">
                <id column="id" property="id"></id>
                <result column="last_name" property="lastName"></result>
                <result column="gender" property="gender"></result>
                <result column="last_name" property="email"></result>
            </case>
        </discriminator>

    </resultMap>
  • 标签

​ column:表示要判断的是哪一列

​ javaType:表示列值的类型

​ value:表示列值

​ resultType:表示将case包围的该对象返回给谁

4、分页查询

可以降低数据库查询压力,将大量的查询,分成小部分来查询

5、方法中的参数处理

5.1、单个参数

<!--    public User getUserById(String id);  -->
    
<select id="getUserById" resultMap="UserMap">
    SELECT * from user where id = #{id2312312sdfsadf}
</select>
  • 对于含有单个参数的方法,Mybatis不做处理,#{},大括号内可以写任意值,sql中传入的都是方法中的参数

5.2、多个参数

#{}直接传参数名会报错:Parameter ‘id’ not found. Available parameters are [arg1, arg0, param1, param2]

5.2.1显示的多个参数
  • 对于方法中传入多个参数的情况,参数都会被封装到一个map中,sql中可以通过#{key}的形式来取参数value; 相当于去map中取值

  • 可以用param1…paramN来指定sql中待传入的参数,也可以用arg0,arg1来指定

key : param1…paramN arg0…argN

value : 方法中传入的值

例子

<!--public User getUserByTw(Integer id,String name);-->
<select id="getUserByTw" resultType="User">
    SELECT * from user where id = #{arg0} and name = #{arg1}
</select>
  • 还可以用注解@param来为方法中的参数命名,那么sql语句中待传入的参数值就是@param()括号中的值

key : @param(“ ”) 括号中的命名

value :方法中传入的值

方法:
public User getUserByTw(@Param("id") Integer id, @Param("name") String name);

xml配置:
    <!--public User getUserByTw(@Param("id") Integer id, @Param("name") String name);-->
    <select id="getUserByTw" resultType="User">
        SELECT * from user where id = #{param1} and name = #{param2}
    </select>
5.2.2 隐式的多个参数

比如方法中形参是pojo/Map/Collection,其实这时候方法中传进来也是多个参数,但是在方法中又只体现传入一个值

此时的key就是直接对应于pojo/map中的key

  • 如果要传入的值在pojo中,可以在方法中直接传入一个pojo对象
  • 如果要传入的值不在pojo中,可以在方法中传递一个map对象,相当于去map中取值

举例

mapper

public User getUserByMap(Map<String,Object> map);

(mapper.xml)

    <!--    public User getUserByMap(Map<String,Object> map);-->
    <select id="getUserByMap" resultType="User">
        SELECT * from #{tableName} where id = #{id} and name = #{name}
// #{key} 相当于去map中取值
    </select>

(测试类)

    @Test
    public void testGetByMap() {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String,Object> map = new HashMap<String, Object>();
        map.put("id",1);
        map.put("name","狂神");
        map.put("tableName","user")
        User userByMap = mapper.getUserByMap(map);
        System.out.println(userByMap);
    }
}
5.2.3特殊
public User getUser(@Param("id") Integer id,@Param("user") User u);

取值:id ===> #{id} name ===> #{user.name}

  • 对于传入Collection(List,Set)类型或者数组,也会把他们封装在map中

    取值方式:

    Collection ===> collection) ; 对于List还可以这样取List ===> list

    数组 ===> array

举例:方法中传入List

public User getUser(List<User> users)

取值:取第一个值 #{list[0]}

6、#{}和${}的区别

  • #{}是采用预编译的方式,可以防止sql注入,只能取参数位置的值

  • ${}是取出来的值直接拼接在sql语句中,会有sql注入问题

    <!--    public User getUserById(String id);  -->
    <select id="getUserById" resultType="User">
        SELECT * from user where id = ${id}
    </select>

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

  • 大多数情况使用#{}的方式取值,但有时候会用到${}的方式取值,比如说要拼接sql语句中的表名时(上面的5.2.2中是一个例子)
  • 还有就是使用order by的时候
select * from ${tableName} where id = #{id}
select * from user order by ${name}

7、动态sql语句

  • 可以实现sql的复用

  • 根据不同的查询条件,使用同一个条sql语句,查询出不同的结果

7.1 if

    <!--public List<Blog> getBlobIf(Map map);-->

    <select id="getBlobIf" resultType="Blog">
        SELECT * from mybatis.blog
        <where>
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and autore = #{author}
            </if>
        </where>
    </select>
  • 标签

表示:where后面的语句如果有多余的and/or,会将其自动去除;如果where后面没有语句,则将where自动去除

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

trim标签这样使用效果和where的效果相同

7.2 choose、when

<!--public List<Blog> getBlobSwitch(Map map);-->

    <select id="getBlobChoose" resultType="Blog">
        SELECT * from mybatis.blog
        <where>
            <choose>
                <when test="title != null">
                    title = #{title}
                </when>
                <when test="author != null">
                    and author = #{author}
                </when>
                <otherwise>
                    views = #{views}
                </otherwise>
            </choose>
        </where>
    </select>
  • 如同 switch-case,如果前面的when中有一个满足,则不会再去执行下面的匹配

7.3 set

 <!--public int updateBlob(Map map);-->

    <update id="updateBlob">
        UPDATE mybatis.blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="author != author">
                author = #{author},
            </if>
        </set>
        where id = #{id}
    </update>

:会自动去掉set后面的逗号

<trim prefix="SET" suffixOverrides=",">
    ...
<trim>

trim在这里使用的效果和set相同

7.4 提取sql公共片段

 	<sql id="if-title-author">
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and autore = #{author}
        </if>
    </sql>
  • 在mapper.xml中有公共的片段,可以将其提取出来,然后在sql中使用

7.5 for-each

 <!--select * from mybatis.blog where (id = 1 or id=2 or id=3 );-->

   	<!--public List<Blog> getBlobForEach(Map map);-->

    <select id="getBlobForEach" resultType="Blog">
        SELECT * from mybatis.blog
        <where>
            <foreach collection="ids" item="id" index="index"
            open="(" separator="or" close=")">
                id = #{id}
            </foreach>
        </where>
 </select>
  • 标签

collection:表示map中的一个元素(在这里是一个集合)

item:表示集合中的每一项元素

如果不是最后一项,会使用separator="or"进行拼接,否则使用close结束

8、缓存

8.1 什么是缓存

  • 存在内存中的临时数据

  • 数据库的查询会占用资源,需要使用缓存来解决这个问题

  • 默认情况,只有一级缓存开启,就是在一个sqlSession中

  • 二级缓存是需要手动开启,它可以在一个namespace(mapper接口)方法中有效

8.2 一级缓存

  • 在同一个sqlSession中有效

  • 一级缓存默认开启,无法关闭

  • 失效的几种情况

    • 进行了增删改
    • 不是同一次sqlSession
    • 查询的不是同一个东西
    • 手动清理了缓存

8.3 二级缓存

	<settings>
        <setting name="cacheEnabled" value="true"></setting>
    </settings>

在xml中开启二级缓存

<cache/>

在对应的mapper中开启二级缓存

  • 作用域:可作用于同一个namespace中
  • 所有的数据都会先放在一级缓存中
  • 只有会话关闭,才会将数据提交到二级缓存中
  • 如果有两个会话,会话1查询数据后关闭连接,会话2查询相同的数据才能使用二级缓存

8.4 缓存执行原理

  • 先去二级缓存中查找,再去一级缓存中查找,再去数据库中查找

9、mapper.ml文件无法被maven加载到target文件中的问题

  • 在pom中配置以下即可
<build>
<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
        <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
    </resource>
</resources>
</build>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值