第三章 基础拓展(一)

3.1 typeAlias
3.1.1为什么使用?
首先先来看一个问题:
在这里插入图片描述
在我们的查询标签中,需要返回一个数据类型,前面都是使用类的全限定名进行表示,这样写多了也会觉得很烦,很冗余,其实也就是在查询的时候需要用到这个返回类型。
3.1.2如何使用?
需要在全局配置文件(此处代指上面的mybatis-config.xml文件),进行配置。
配置方式1:在这里插入图片描述
配置方式2:
在这里插入图片描述
配置方式3:
在这里插入图片描述

方式3应该避免使用。
在select中可以简单的引用一下就可以了。
在这里插入图片描述
注:别名是不区分大小的。
3.1.3系统自带的别名
1.基本数据类型的别名在类型前面加_
例如:int ----_int long — _long
2.包装数据类型的别名将首字母小写。
例如:Integer --integer Long-- long
3.集合类型别名也将首字母小写。
例如:List list
ArrayList arraylist
需要用到可以到他官网去查询下
3.1.4Properties
属性配置,此处需要在全局配置文件中进行配置(此处代指mybatis-config.xml)。
配置的文件上面进行申明,下面进行引用。
在这里插入图片描述

在这里插入图片描述
但是此时感觉到并没什么用,只是放在上面更加清晰一点罢了。
接下来需要讲解的是:在这里插入图片描述
在mybatis-config.xml文件中进行引用,这种方式才是比较推荐的,也是实施人员最喜欢看的,还有一个url属性,表示可以从网络或者本地磁盘进行加载文件。
3.2Mapper接口和原理
3.2.1为什么使用?

在这里插入图片描述
我们之前的查询操作是这样的,接下来就通过这个查询代码分析下存在的问题。
1.需要使用namespace命名空间加上id去查询,从一个字符串中就可以体现出,这样很容易写错,系统也不去检查,只有在程序运行的时候才能发现。
2.传入的参数2,就是限定条件,系统也不会去检查(底层设计的就是Object对象),也只有在运行的时候才能发现。
3.代码重复,我们在获取连接对象,关闭资源,都是重复的,只有具体的增删改查操作不一致。
3.2.2如何使用?
首先定义一个接口,代码如下:
在这里插入图片描述
在mapper的xml文件中namespace中名称就应该用接口的全限定名。
在mapper的xml文件中的id应该对应接口中的方法名。
最后不要忘了再全局配置文件中:
配置一下
上述代码写完了,接下来进行测试:
在这里插入图片描述
可以看出来运行和结果也是没问题的,那么来简单分析下:
首先调用getMapper()方法传递一个EmployeeMapper的字节码对象,然后获取到EmployeMapper接口的全限定名,不就是可以得到前面的namespace的字符串吗?
然后再调用他的方法,也就是拼凑成了一开始selectOne(String string ,Object object)方法中的第一个参数,这样就很容易理解了。
底层实现:
使用了一种动态代理的设计模型,不需要掌握,知道就可以。
动态代理就不进入深入讲解了。
补充:
在上面增删改的接口方法上面可以使用返回值,Long ,Integer,Boolean包装类型和基本类型都可以,mybatis会自动返回,比如Long会返回受影响的行数,Boolean会去判断如果影响的行数>0则回返回true。
3.3resultMap
3.3.1简单使用resultMap

演示问题:
在之前我们使用的javabean封装对象的名称一定需要和数据库中的字段名称一致,若是不一致则会出现数据无法返回封装到javabean对象中,先来演示这个问题。

在这里插入图片描述
设计表的前面我都加了一个_。查询语句也要改一下。

<select id="selectAll" resultType="com.mybatis.dmomain.Student">
 SELECT  _id ,_name,_age  FROM  employee WHERE  _id=#{id}
</select>

在这里插入图片描述
可以发现什么结果都没查询到,其实是查询到了,但是在封装的时候出问题了。
将表的结构和查询语句改回一样就可以查询到了。
在这里插入图片描述
简单使用:
resultMap中文意思就是结果映射,就是返回的结果集合和对象的映射。
此处需要在配置文件(此处代指EmployeeMappr.xml文件)。
在这里插入图片描述
引用结果映射:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意:resultMap不能和resultType同时使用,并且resultMap只是用在查询上面。
在标签中,除了result还一个id的属性,他的功能跟result功能类似,但是官方介绍,如果是主键建议使用id属性,会提升一些性能。
3.3.2级联使用resultMap
此处需要新建一张表:
在这里插入图片描述

@Data
public class Teacher {
    private Long id;
    private String name;
}

假设一个学生还可以对应一个老师,或者多个老师,在查询学生信息的时候把学生对应的老师信息也查询出来。
在这里插入图片描述

@Data
public class Student {
    private Long id;
    private String name;
    private Integer age;
//学生对象里面关联老师对象
    private Teacher teacher;
}

在这里插入图片描述
接口方法:

/**
 * 根据传递学生的id查询学生的全部信息
 *
 * @param id 学生id
 * @return 返回学生对象
 */
Student getStudentAndTeacher(Long id);

XML映射文件:

方式1:使用对象.属性去封装
<!---结果集映射-->
<resultMap id="myStudent1" type="student">
    <!--
    column属性:对应数据表查询返回的列名
    property:对应实体类中javaBean属性
    -->
    <id column="s_id" property="id"/>
    <result column="s_name" property="name"/>
    <result column="age" property="age"/>
 <!--此处可以发现property属性中通过对象.属性名去关联另一个对象 -->
    <result column="t_id" property="teacher.id"/>
    <result column="t_name" property="teacher.name"/>
</resultMap>
<select id="getStudentAndTeacher" resultMap="myStudent1">
select s.id as s_id,s.name as s_name,s.age,s.teacher_id,t.id as t_id,t.name as t_name
from student s,teacher t where  s.teacher_id=t.id and s.id=#{id};
</select>

在这里插入图片描述
方式2:使用association 标签

<!--
association:该标签可以封装另一个对象的属性
property:依然是对应一个当前返回类的属性
javaType:表示该属性的类全限定名
column:返回的列名
property:对象中的属性名
-->
<association property="teacher" javaType="com.mybatis.dmomain.Teacher">
    <id column="t_id" property="id"/>
    <result column="t_name" property="name"/>
</association>

效果也是一样的。
方式3使用association 分步查询:
方式2使用的是一个SQL语句,此处也可以使用两步去查询,比如先查询出学生的信息,然后再去根据学生中关联教师的id再去查询教师信息。
此处称为额外SQL,既然Mysql这么强大,那么就可以给我们进行完成这个操作。
做下准备工作:
前面写新建了一个teacher表和实体类,在实际中开发中既然有一个表,那么习惯的就会将该表对应发mapper接口和映射文件也给写出来。

public interface TeacherMapper {
    /**
     * 根据id去查询数据表中Teacher信息
     *
     * @param id 唯一标识
     * @return 单个Teacher对象
     */
    Teacher getTeacher(Long id);
}
XML映射文件:
<select id="getTeacher" resultType="com.mybatis.dmomain.Teacher">
   SELECT  id,name  FROM  teacher WHERE  id=#{id}
</select>

在学生的实体类中新增加一个属性,用于封装返回的结果集

@Data
public class Student {
    private Long id;
    private String name;
    private Integer age;
     //新增属性
    private Long teacher_id;
    private Teacher teacher;
}
<!--
使用association进行分步查询:
1.根据学生id查询出学生的信息
2.根据查询到学生信息中关联教师的id,再去查询教师的信息
3.将查询到教师信息设置到学生对象中
-->
<resultMap id="myStudent2" type="student">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="age" property="age"/>
    <result column="teacher_id" property="teacher_id"/>
    <!--property:实体类中对象
       select:发送查询语句
       column:将返回列的值传递过去
    -->
   <association property="teacher" select="com.mybatis.mapper.TeacherMapper.getTeacher"
                column="teacher_id"/>
</resultMap>
<select id="getStudentByIdStep" resultMap="myStudent2">
 SELECT  id,name,age,teacher_id FROM  student WHERE  id=#{id}
</select>

select id="getTeacher" resultType="com.mybatis.dmomain.Teacher">
   SELECT  id,name  FROM  teacher WHERE  id=#{id}
</select>

在这里插入图片描述
分步查询和延迟加载:
前面在使用方式3发送额外SQL查询的时候,不管每次是否需要查询教师的信息,Mybatis每次都会去关联查询教师的信息,这样当我们不需要的时候则会浪费性能。
首先重景在现:

@Test
void testStudent() {
    SqlSession session = MyBatisUtil.getSession();
    StudentMapper mapper = session.getMapper(StudentMapper.class);
    Student student = mapper.getStudentByIdStep(2L);
//此处我只想获取员工的年龄信息
    System.out.println(student.getAge());
    session.close();
}  

在这里插入图片描述
可以发现我并没有调用Teacher的get方法,并没有想去获取该属性,他就将我给查询出来了。
只需要在全局配置文件中

<settings>
开启懒加载模式
    <setting name="lazyLoadingEnabled" value="true"/>
不积极的去查找关联属性
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

3.3.3collection标签
该标签看名字就知道主要是来封装集合操作的。
表内容增加下:
在这里插入图片描述
接口方法

/**
 * 根据教师的id查询该教师关联的所有学生信息
 *
 * @param id 教师id
 * @return 学生信息
 */
Teacher getTeacherPlus(Long id);



 <resultMap id="myTeacher" type="com.mybatis.dmomain.Teacher">
    <!--封装查询到的教师信息-->
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <!--封装查询到学生的信息
collection :集合结果集
ofType:      集合中对象类型
-->
    <collection property="students" ofType="student">
        <id column="s_id" property="id"/>
        <result column="s_name" property="name"/>
        <result column="age" property="age"/>
        <result column="teacher_id" property="teacher_id"/>
    </collection>
</resultMap>
<select id="getTeacherPlus"  resultMap="myTeacher">
 select s.id as s_id,s.name as s_name,s.age,s.teacher_id,t.id,t.name
 from student s,teacher t
 where s.teacher_id=t.id  and t.id=#{id};
</select>

@Data
public class Teacher {
    private Long id;
    private String name;
    //一个老师中可以对应多个学生对象
    private List<Student> students = new ArrayList<>();
}

测试方法

@Test
void testTeacher() {
    SqlSession session = MyBatisUtil.getSession();
    TeacherMapper mapper = session.getMapper(TeacherMapper.class);
    Teacher teachers = mapper.getTeacherPlus(2L);
    List<Student> students = teachers.getStudents();
    for (Student s : students) {
        System.out.println(s);
    }
    session.close();
}

在这里插入图片描述
分步查询:
鉴于上面的分步查询,此时也来尝试下:
接口方法:

/**
 * 查询该教师所关联的所有学生
 *
 * @param id 教师id
 * @return 教师中包含的学生
 */
Teacher getTeacherInStudentByStep(Long id);
XML映射文件:
<!---结果集映射-->
<resultMap id="teacherIndStudent" type="com.mybatis.dmomain.Teacher">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <collection property="students"
                select="com.mybatis.mapper.StudentMapper.getStudentByTeacherID" column="id"/>
</resultMap>
<select id="getTeacherInStudentByStep" resultMap="teacherIndStudent">
   SELECT  id,name FROM  teacher WHERE id=#{id}
</select>

<select id="getStudentByTeacherID" resultType="com.mybatis.dmomain.Student">
    SELECT  id,name,age,teacher_id FROM  student WHERE   teacher_id=#{id}
</select>

测试方法:

   @Test
    void testTeacher() {
        SqlSession session = MyBatisUtil.getSession();
        TeacherMapper mapper = session.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacherInStudentByStep(1L);
        System.out.println(teacher.getName());
//        List<Student> students = teacher.getStudents();
//        for (Student s : students) {
//            System.out.println(s);
//        }
        session.close();
    }

在这里插入图片描述
可以看到他也只是执行了一条SQL,也是按需加载。
此处补充一个知识点:
在上面我们使用了分步查询,都有一个column属性,但是传递的都是一个值,此处的需求就是传递多个值过去.

    select="com.mybatis.mapper.StudentMapper.getStudentByTeacherID" column="id"/>
</resultMap>
column="{key1=column1,key2=column2}"

这样传递即可,演示下:
在这里插入图片描述

在这里插入图片描述
即使取错了key,不会报错,就是获取不到值。
在这里插入图片描述
可以单独的开启是否启动懒加载模式:
在这里插入图片描述
3.4参数处理
3.4.1为什么使用?

首先来看一个查询操作:
在这里插入图片描述
此处我们做查询,只能传递一个参数,那么我们需要传递多个参数呢?
此处先说一下:
1.针对传递单个基本的数据类型

<select id="selectone" resultMap="baseResultType">
 SELECT  _id,_name,_age FROM  student WHERE  _id=#{xxx}
</select>

#{}里面的属性名可以任意写都可以映射,任意写也是符合标识符命名规范的。
2.传递javaBean对象

<select id="selectone" resultMap="baseResultType">
 UPDATE  student set id=#{id},name=#{name},age=#{age}
 WHERE id=#{id}
</select>

此时传递是对象,会去取getter的属性值,若是没有则会报错。
3.传递Map对象

 此处会根据key的值去查询value的值,需要在取值的时候用传递的key。

4.传递@Para(“key”)注解

 此时取值则要根据注解中的key进行取值。

3.4.2使用POJO封装
先做一些准备工作,下面处理方式也会用。
1.新建一个实体类:
EmployeeLogin,封装getter和setter方法以及提供有参和无参构造器。
2.接口中的方法更改下:
EmployeeLogin selectOne(EmployeeLogin employeeLogin);
此时他需要接收一个对象,此处我们就来模拟一个登陆操作。
3.将数据表中添加两个字段并且给些数据。
在这里插入图片描述
4.修改Mapper.xm中的SQL查询语句。

<select id="selectOne" resultType="com.mybatis.entry.EmployeeLogin">
    SELECT  * FROM  employe WHERE   username=#{username} AND 
     password=#{password}
</select>

准备工作完成了,接下来就是调用。
在这里插入图片描述
可以发现这样也是可以的,但是如果有很多个需要传递参数就得创建很多个对象,这样下去也比较麻烦。
3.4.3使用Map进行封装
在这里插入图片描述
在这里插入图片描述
3.4.4使用注解@Param("")
在这里插入图片描述
可以发现也是可以的,这个也是实际开发中最常用的一种方式,需要重点去掌握。
传递集合的时候肯定是需要 用到这个注解的。
注意:注解中传递的字符串需要和执行#{}括号中的字符串一样。
3.4.5#和$区别
这两个符号在前面都有使用过,此处就来讲解下他们的区别。
通过运行日志可以看出:
使用#:

 SELECT id,username,password FROM userinfo WHERE 
 username=? AND password=?    Parameter:root(String) , 12356(String)

使用$:

 SELECT id,username,password FROM userinfo WHERE 
 username=root AND password=123456

相同点:
他们都可以从对象中取出数据。
不同点:
1.使用#传递的参数会先转换为占位符,再通过设置占位符参数的方式进行设置值。
2.使 传 递 的 参 数 , 会 直 接 把 解 析 出 来 的 参 数 作 为 S Q L 语 句 的 一 部 分 。 如 何 选 择 的 问 题 : 当 我 们 需 要 传 递 的 参 数 作 为 S Q L 语 句 一 部 分 的 时 候 需 要 使 用 传递的参数,会直接把解析出来的参数作为SQL语句的一部分。 如何选择的问题: 当我们需要传递的参数作为SQL语句一部分的时候需要使用 ,SQL:SQL使符号,当仅仅要设置参数的时候使用#即可。
下面演示下:根据id进行升序排序。
接口方法:

void select(@Para(“condition”) String condition);

xml文件:

SELECT * FROM student ORDER BY  id   ${condition};

调用:

select(“ASC”)

执行结果:

SELECT * FROM student ORDER BY  id   ASC;
<select id="selectAll" resultType="com.mybatis.dmomain.Student">
 SELECT  _id  FROM  employee WHERE  id=#{id,jdbcType=NULL}
</select>

对于传递null的时候,oracle数据库不支持,无法进行映射,需要改一下,但是一般不去传递null就可以了。
3.4.6Mybatis内置参数
_parameter:
当传递单个数据的时候,_parameter就代指这个参数
当传递多个数据的时候,_parameter代指的就是这个参数的key

_databaseId:
代表当前数据库的配置的值。

<databaseIdProvider type="DB_VENDOR">
  <property name="SQL Server" value="sqlserver"/>
  <property name="DB2" value="db2"/>        
  <property name="Oracle" value="oracle" />
</databaseIdProvider>

3.5 Mybatis的插件
开发工具使用的是idea,安装下插件方便后续更好的开发。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
写代码会有一些实质性的提示,比如你在接口中定义了一个方法,在mapper文件中没有定义该方法他会直接报错,你点击可以直接给你生成。
在这里插入图片描述
3.5.1Log4j日志打印
在这里插入图片描述
log4j.properties:
放在resources资源目录下

#所有日志
log4j.rootLogger = DEBUG,stdout,file,WARN,DAILY_ALL
log4j.logger.org.apache.ibatis=warn
log4j.logger.java.sql=warn
log4j.logger.org.springframework=warn

# Druid
log4j.logger.druid.sql=DEBUG
log4j.logger.druid.sql.DataSource=warn
log4j.logger.druid.sql.Connection=warn
log4j.logger.druid.sql.Statement=DEBUG
log4j.logger.druid.sql.ResultSet=warn
#设置包名的输出级别
log4j.logger.cn.wdq=DEBUG

#控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=DEBUG
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss}[ %p ]%m%n

#所有文件输出
log4j.appender.DAILY_ALL=org.apache.log4j.DailyRollingFileAppender
log4j.appender.Threshold=WARN
log4j.appender.DAILY_ALL.layout=org.apache.log4j.PatternLayout
log4j.appender.DAILY_ALL.layout.ConversionPattern=%p %d{yyyy-MM-dd HH:mm} %-50.50c(%L) - %m%n%n
log4j.appender.DAILY_ALL.File=D:/dispatch.log

3.5.2LomBok插件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
安装完重启下IDEA就可以用了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值