笔记代码

分割线

配置解析

MyBatis-Config.xml这个文件,配置层级如下

  • configuration(配置)

    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)*
    • objectFactory(对象工厂)*
    • plugins(插件)*
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)
  • '\*' 的是了解即可的.


environments

  • MyBatis 可以适应连接多个环境,但是每个 SqlSessionFactory 只能选择一种环境

    <environments default="development">
    <environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url"
    value="jdbc:mysql://localhost:3306/mybatis?userSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
    </dataSource>
    </environment>
    <environment id="test">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url"
    value="jdbc:mysql://localhost:3306/mybatis?userSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
    </dataSource>
    </environment>
    </environments>
  • MyBatis 默认事务管理器是 JDBC,数据源类型可用 POOLED/UNPOOLED/JNDI

    常见的数据源: dbcp, c3p0, druid

    数据源有哪几种?


properties

  • 可以通过 properties 属性来实现引用配置文件,比如把上方的 xml 配置抽离到 db.properties

    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url"
    value="jdbc:mysql://localhost:3306/mybatis?userSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>

    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    <!--引入外部配置文件,同时增添一些配置-->
    <properties resource="db.properties">
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
    </properties>

    <environments default="development">
    <environment id="development">
    <transactionManager type="JDBC"/>
    <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>

typeAliases

  • 可以给配置起一个别名,或者扫描导入 pojo 包

    <typeAliases>
    <!--相当于<typeAlias type="pojo.User" alias="user"/>-->
    <typeAlias type="pojo.User"/>

    <!--在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名.比如pojo.User别名为user-->
    <package name="pojo"/>
    </typeAliases>
  • 注解方式起别名

    @Alias("user")
    public class User {
    ...
    }
  • MyBatis 还有一些默认的别名

    20210507212138

Settings

  • 会改变 MyBatis 运行状态的配置

  • 需要修改时找文档就行.


plugins

  • mybatis-generator-core
  • mybatis-plus
  • 通用 mapper

mappers

  • 注册绑定我们的 Mapper.xml 文件,有下面三种方式:

    这三种不能同时导入同一个资源,会冲突报错

    <mappers>
    <!--
    1. (推荐)
    每一个Mapper.xml都需要在MyBatis核心配置文件中注册
    -->
    <mapper resource="dao/UserMapper.xml"/>

    <!--
    2.
    使用class文件绑定注册
    注意:接口和他的Mapper配置文件必须同名且在同一个包下
    -->
    <mapper class="dao.UserMapper"/>

    <!--
    3.
    使用包扫描进行注入
    -->
    <package name="dao"/>
    </mappers>

作用域/生命周期

20210508000956 20210508000002
  • SqlSessionFactoryBuilder: 创建 SqlSessionFactory 之后就被消除的局部变量

  • SqlSessionFactory

    可以想象为:数据库连接池

    被创建之后在应用运行期间一直存在

    应用作用域,使用(静态)单例模式


  • SqlSession

    连接到连接池的一个请求

    线程不安全,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。

    用完就需要关掉,否则占用资源.

分割线

属性名和字段名不一致的问题

问题展示

public class User {
private int id;
private String name;
//password - pwd 属性名和字段名不一致
private String password;
}
  • 结果: 在数据库查不到名为"password"的字段,所以 password 显示为 null

    User(id=1, name=张三, password=null)
    User(id=2, name=李四, password=null)
    User(id=3, name=王五, password=null)
    User(id=4, name=赵六, password=null)
    User(id=6, name=王虎, password=null)

解决办法

起别名

select * from user where id = #{id}

select id,name,pwd from user where id = #{id}

resultMap

MyBatis 中最重要最强大的元素。

<resultMap id="userResultMap" type="pojo.User">
<!--
property: User中的属性名
column: 数据库的字段名
只需要设置这条名字不一样的映射
-->
<result property="password" column="pwd"/>
</resultMap>

<select id="getUserList" resultMap="userResultMap">
select *
from User
</select>

分割线

日志

简介

  • 用来查看运行状态,排错.

  • 之前用的是 sout,debug 这种,现在出现了日志工厂,方便做日志

    • SLF4J

    • LOG4J 【掌握】

    • LOG4J2

    • JDK_LOGGING

    • COMMONS_LOGGING

    • STDOUT_LOGGING 【掌握】

    • NO_LOGGING


STDOUT_LOGGING

  • 在 MyBatis-config.xml 中写入配置 (注意 settings 标签所处上下位置不要错)

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

  • 自动添加这种日志

    Opening JDBC Connection
    Sun May 09 23:57:40 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
    Created connection 1524305331.
    Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5adb0db3]
    ==> Preparing: select * from User
    ==> Parameters:
    <== Columns: id, name, pwd
    <== Row: 1, 张三, 123456
    <== Row: 2, 李四, 123456
    <== Row: 3, 王五, 123456
    <== Row: 4, 赵六, 123456
    <== Row: 6, 王虎, 789
    <== Total: 5
    User(id=1, name=张三, password=123456)
    User(id=2, name=李四, password=123456)
    User(id=3, name=王五, password=123456)
    User(id=4, name=赵六, password=123456)
    User(id=6, name=王虎, password=789)
    Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5adb0db3]
    Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5adb0db3]
    Returned connection 1524305331 to pool.

Log4j

更加细化,配置化的日志工厂

  • 依赖:

    <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
    </dependency>

  • 配置文件 src/main/resources/log4j.properties

    #将等级为DEBUG的日志信息输出到console和file
    log4j.rootLogger=DEBUG,console,file

    #日志输出级别
    log4j.logger.org.mybatis=DEBUG
    log4j.logger.java.sql=DEBUG
    log4j.logger.java.sql.Statement=DEBUG
    log4j.logger.java.sql.ResultSet=DEBUG
    log4j.logger.java.sq1.PreparedStatement=DEBUG

    #控制台输出的相关设置
    log4j.appender.console = org.apache.log4j.ConsoleAppender
    log4j.appender.console.Target = System.out
    log4j.appender.console.Threshold=DEBUG
    log4j.appender.console.layout = org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

    #文件输出的相关设置
    log4j.appender.file = org.apache.log4j.RollingFileAppender
    #输出路径
    log4j.appender.file.File=./log/rzp.log
    log4j.appender.file.MaxFileSize=10mb
    log4j.appender.file.Threshold=DEBUG
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

  • 测试 src/test/java/Log4jTest.java

    日志有三个输出等级

    import dao.UserMapperTest;
    import org.junit.Test;
    import org.apache.log4j.Logger;

    public class Log4jTest {
    @Test
    public void test() {
    UserMapperTest.getUserList();
    Logger logger = Logger.getLogger(Log4jTest.class);
    logger.info("info: 测试log4j");
    logger.debug("debug: 测试log4j");
    logger.error("error:测试log4j");
    }
    }
  • 结果日志

    [DEBUG][21-05-11][org.apache.ibatis.logging.LogFactory]Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
    [DEBUG][21-05-11][org.apache.ibatis.logging.LogFactory]Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
    [DEBUG][21-05-11][org.apache.ibatis.datasource.pooled.PooledDataSource]PooledDataSource forcefully closed/removed all connections.
    [DEBUG][21-05-11][org.apache.ibatis.datasource.pooled.PooledDataSource]PooledDataSource forcefully closed/removed all connections.
    [DEBUG][21-05-11][org.apache.ibatis.datasource.pooled.PooledDataSource]PooledDataSource forcefully closed/removed all connections.
    [DEBUG][21-05-11][org.apache.ibatis.datasource.pooled.PooledDataSource]PooledDataSource forcefully closed/removed all connections.
    [DEBUG][21-05-11][org.apache.ibatis.transaction.jdbc.JdbcTransaction]Opening JDBC Connection
    [DEBUG][21-05-11][org.apache.ibatis.datasource.pooled.PooledDataSource]Created connection 24650043.
    [DEBUG][21-05-11][org.apache.ibatis.transaction.jdbc.JdbcTransaction]Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@178213b]
    [DEBUG][21-05-11][dao.UserMapper.getUserList]==> Preparing: select * from User
    [DEBUG][21-05-11][dao.UserMapper.getUserList]==> Parameters:
    [DEBUG][21-05-11][dao.UserMapper.getUserList]<== Total: 5
    [DEBUG][21-05-11][org.apache.ibatis.transaction.jdbc.JdbcTransaction]Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@178213b]
    [DEBUG][21-05-11][org.apache.ibatis.transaction.jdbc.JdbcTransaction]Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@178213b]
    [DEBUG][21-05-11][org.apache.ibatis.datasource.pooled.PooledDataSource]Returned connection 24650043 to pool.
    [INFO][21-05-11][Log4jTest]info: 测试log4j
    [DEBUG][21-05-11][Log4jTest]debug: 测试log4j
    [ERROR][21-05-11][Log4jTest]error:测试log4j

分割线

分页

  • 简单的分页查询,可能会有报错,但是可以正常运行

    List<User> getUsersByLimit(Map<String, Integer> map);
    <!--分页查询-->
    <select id="getUsersByLimit" parameterType="map" resultType="pojo.User">
    select *
    from mybatis.user
    limit #{startIndex},#{pageSize}
    </select>
    @Test
    public void getUserByLimit() {
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    HashMap<String, Integer> map = new HashMap<>();
    map.put("startIndex", 1);
    map.put("pageSize", 2);

    List<User> list = mapper.getUsersByLimit(map);
    for (User user : list) {
    System.out.println(user);
    }
    }