Mybatis优化,添加日志,给实体类起别名,联表查询,xml特殊字符

  • Mybatis优化
  • 添加日志
  • 解决属性名和字段名不一致的情况
  • 为实体类起别名(不建议使用)
  • 实体的属性和数据库表的字段不一致
  • 联表查询
  • 多对一
  • 创建对应的实体类
  • 映射文件
  • 一对多
  • xml碰到特殊字符如何处理


Mybatis优化

可以把数据源的信息抽取到db.properties文件中。
db.properties文件
jdbc.driverName:jdbc驱动
jdbc.url:数据库的路径
jdbc.userName:数据库用户的账户
jdbc.passWord:数据库用户的密码
///代表localhost:3306
以下两种写法是一个意思

jdbc.url=jdbc:mysql:///mybatis?characterEncoding=utf8&useUnicode=true&useOldAliasMetadataBehavior=true&useSSL=false
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8&useUnicode=true&useOldAliasMetadataBehavior=true&useSSL=false

db.properties文件

jdbc.driverName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis?characterEncoding=utf8&useUnicode=true&useOldAliasMetadataBehavior=true&useSSL=false
jdbc.userName=root
jdbc.passWord=root

再db.properties文件中引入mybatis-config.xml文件中

<properties resource="db.properties"/>

注意:这里的value要用${},中间写引入db.properties文件的属性,如下:

<property name="driver" value="${jdbc.driverName}"/>
         <!--  ppp代表连接数据库的表-->
 <property name="url" value="${jdbc.url}"/>
         <!--  username代表数据库的用户名-->
<property name="username" value="${jdbc.userName}"/>
        <!--  password代表数据库的密码-->
<property name="password" value="${jdbc.passWord}"/>

整体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>
<!--    引入properties文件-->
    <properties resource="db.properties"/>
    <environments default="development">
        <environment id="development">
            <!--  JDBC:代表使用的事务管理类型,默认打开事务,操作之后需要手动提交-->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverName}"/>
                <!--  ppp代表连接数据库的表-->
                <property name="url" value="${jdbc.url}"/>
                <!--  username代表数据库的用户名-->
                <property name="username" value="${jdbc.userName}"/>
                <!--  password代表数据库的密码-->
                <property name="password" value="${jdbc.passWord}"/>
            </dataSource>
        </environment>
    </environments>
<!--    将mapper映射放入mybatis.xml中-->
    <mappers>
        <mapper resource="mapper/ClassMapper.xml"/>
    </mappers>
</configuration>

添加日志

(1)在pom.xml中引入log4j文件

<!--   引入log4j文件 -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

(2)创建日志的配置文件 log4j.properties

log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

控制台输出如下:

2021-03-22 10:03:25,494 [main] DEBUG [com.zz.dao.ClassDao.findClassById] - ==>  Preparing: SELECT * from class c, teacher t ,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=1 
2021-03-22 10:03:25,514 [main] DEBUG [com.zz.dao.ClassDao.findClassById] - ==> Parameters: 
2021-03-22 10:03:25,534 [main] DEBUG [com.zz.dao.ClassDao.findClassById] - <==      Total: 3
Clazz(cid=1, cname=bj_a, teacher=Teacher(tid=1, tName=LS1), students=[Student(sid=1, sName=xs_A, classId=1), Student(sid=2, sName=xs_B, classId=1), Student(sid=3, sName=xs_C, classId=1)])

解决属性名和字段名不一致的情况

为实体类起别名(不建议使用)

1.在mybatis-config.xml
(1)给单个类起别名

<!--给单个类起别名-->
<typeAliases>
    <typeAlias type="com.zz.entity.User" alias="User"/>
</typeAliases>

(2)给指定包下的所有类起别名,类名就是别名
resultType中填的就是mybatis-config.xml中 alias="User"的User

<!--给指定包下的类起别名,就是类的名称-->
<typeAliases>
        <package name="com.zz.entity" />
</typeAliases>

2.在mapper.xml映射文件中
resultType中填的就是该类

<!--    给单个类起别名-->
<select id="selectAll" resultType="User">
    select * password from user
</select>

resultType中填的就是该类

<!--给指定包下的类起别名,就是类的名称-->
<select id="selectAll" resultType="User">
    select *  from user
</select>

实体的属性和数据库表的字段不一致

(1)为查询的结果起别名-----与属性名一致。

<!--给字段起别名-->
<select id="findClassById" resultType="Clazz">
 	select c_id cid,c_name cname,teacher_id teacherId from class c ,teacher t where c.teacher_id=t.t_id and c_id=#{cid}
</select>

(2)使用resultMap来创建属性与字段的映射关系
id:代表主键
result:代表其他字段
column:代表数据库字段
property:映射数据库列的字段或属性(代表实体类字段)
resultMap 里面的id代表它的标识,type代表使用哪种类作为其映射的类,可以是别名或者全限定名
resultMap 里面的type代表使用哪种类作为其映射的类,可以是别名或者全限定名。(java实体类的类型)
resultMap 与resultType两者只能用一个

<!--    type表示java实体类的类型-->
<resultMap id="BaseMap" type="com.zz.entity.User">
<!--        id表示主键
column:表示字段
property:实体类的属性
-->
   <id column="u_id" property="id"/>
<!--        result表示其他字段-->
   <result column="u_username" property="username"/>
   <result column="u_password" property="password"/>
</resultMap>

<!--    给查询的结果起别名-->
<select id="selectAll" resultMap="BaseMap">
    select *  from users
</select>

联表查询

多对一

(1)表与表之间的关系------->外键【逻辑外键】
数据库表teacher

CREATE TABLE teacher(
t_id INT PRIMARY KEY AUTO_INCREMENT,
t_name VARCHAR(20)
);

//teacher     class  一对多
CREATE TABLE class(
c_id INT PRIMARY KEY AUTO_INCREMENT,
c_name VARCHAR(20),
teacher_id INT  -- 外键
);
ALTER TABLE class ADD CONSTRAINT fk_teacher_id FOREIGN KEY (teacher_id)
REFERENCES teacher(t_id); 
INSERT INTO teacher(t_name) VALUES('LS1');
INSERT INTO teacher(t_name) VALUES('LS2');
INSERT INTO class(c_name, teacher_id) VALUES('bj_a', 1);
INSERT INTO class(c_name, teacher_id) VALUES('bj_b', 2);

(2)java实体类如何维持这种关系。

Teacher {tid, tname}
Class {cid,cname,Teacher teacher}
-->class 只包含老师id号。 多对一 可以在多的实体中添加一的实体类对象。

(3)要求根据班级号 查询班级信息并带上老师的信息。

创建对应的实体类

(1)Clazz实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Clazz {
    private int cid;
    private String cname;
//    该班级对应的老师信息
    private Teacher teacher;
    
//    表示该班级下所有的学生信息
    private List<Student> student;
}

Teacher实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int tid;
    private String tname;
}

映射文件

(1)第一种方法:联表查询只要引用的是对象就用resultMap
引入的是对象就用association
association :表示一对一关系
association 里面的property代表映射数据库列的字段或属性(代表实体类字段)
association 里面的javaType代表返回类型,跟resultType一个意思
mapper.xml中

<resultMap id="ClazzMap" type="com.zz.entity.Clazz">
          <!--        id代表主键-->
          <id column="c_id" property="cid"/>
          <!--        result代表其他属性-->
          <result column="c_name" property="cname"/>
          <!--        association代表多对一映射-->
          <!--        如果引入的是对象-->
          <association property="teacher" javaType="com.zz.entity.Teacher">
              <!--            该属性的名字与字段的对应关系-->
              <id column="t_id" property="tid"/>
              <result column="t_name" property="tname"/>
          </association>
      </resultMap>
      <!--    只要使用联表查询,必须使用resultMap-->
      <select id="findClassById" resultMap="ClazzMap">
          select * from class c ,teacher t where c.teacher_id=t.t_id and c.c_id=#{cid};
      </select>

(2)两条sql进行查询
mapper.xml中
其中association 多加了两个属性
column:所对应的外键字段名称(数据库字段)把第一次查询的某一个作为第二次查询的值
select:把column列值交给select这个查询语句,填的是第二个查询语句的id,使用另一个查询封装的结果
第二条sql中就不能写resultMap了,写resultType

<resultMap id="classMap" type="Clazz">
    <id column="c_id" property="cid"/>
    <result column="c_name" property="cname"/>
         <!--        一对一关系-->
 <!--        column把第一次查询的某一个作为第二次查询的值
             select把column列值交给select这个查询语句
 -->
	<association property="teacher" javaType="com.zz.entity.Teacher" column="teacher_id" select="findTeacherById" >
      	<id column="t_id" property="tid"/>
      	<result column="t_name" property="tName"/>
	</association>
</resultMap>
<select id="findClassById" resultMap="classMap" >
     select * from class where c_id=#{cid}
</select>
<select id="findTeacherById" resultType="com.zz.entity.Teacher">
     select t_id tid ,t_name tName from teacher  where  t_id=#{tid}
</select>

一对多

数据库表student

CREATE TABLE student(
s_id INT PRIMARY KEY AUTO_INCREMENT,
s_name VARCHAR(20),
class_id INT
);
INSERT INTO student(s_name, class_id) VALUES('xs_A', 1);
INSERT INTO student(s_name, class_id) VALUES('xs_B', 1);
INSERT INTO student(s_name, class_id) VALUES('xs_C', 1);
INSERT INTO student(s_name, class_id) VALUES('xs_D', 2);
INSERT INTO student(s_name, class_id) VALUES('xs_E', 2);
INSERT INTO student(s_name, class_id) VALUES('xs_F', 2);

要求 根据班级id查询班级信息以及该班级下所有的学生信息。
Student 实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private Integer sid;
    private String sName;
    private String classId;
}

mapper.xml中
collection 表示一对多
collection 里面的property代表映射数据库列的字段或属性(代表实体类字段)
collection 里面的ofType代表返回类型,跟resultType一个意思

<!-- 一对多   -->
<resultMap id="classMap" type="com.zz.entity.Clazz">
    <id column="c_id" property="cid"/>
    <result column="c_name" property="cname"/>
        <!--        多对一的映射-->
    <association property="teacher" javaType="com.zz.entity.Teacher">
         <id column="t_id" property="tid"/>
         <result column="t_name" property="tname"/>
    </association>
        <!--        一对多-->
        <!--        ofType/表示集合的泛型-->
	<collection property="student" ofType="com.zz.entity.Student">
         <id column="s_id" property="sid"/>
         <result column="s_name" property="sname"/>
	</collection>
</resultMap>
    <!--    只要使用联表查询,必须使用resultMap-->
<select id="findClassById" resultMap="classMap">
    SELECT * from class c,teacher t ,student s where c.teacher_id=t.t_id
        and c.c_id=s.class_id and c.c_id=1
</select>

xml碰到特殊字符如何处理

(1)可以使用转移字符

实体类字段与ES中字段映射_实体类字段与ES中字段映射

(2)使用CDATA
<![CDATA[sql]]>
mapper.xml中

<!--    查询cid在区间的范围-->
    <select id="findBetweenById" resultMap="classMap">
        <![CDATA[select * from class where c_id>=#{min} and c_id<=#{max}]]>
    </select>