跳至主要內容

MyBatis基础用法总结

Alooc...大约 12 分钟后端框架MybatisMybatis

使用JDBC

1. 使用

	@Test
    public  void testConnection5() throws Exception {
    	//1.加载配置文件
        InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties pros = new Properties();
        pros.load(is);
        
        //2.读取配置信息
        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");

        //3.加载驱动
        Class.forName(driverClass);

        //4.获取连接
        Connection conn = DriverManager.getConnection(url,user,password);
        System.out.println(conn);

    }
user=root
password=root
url=jdbc:mysql://127.0.0.1:3306/yygh_hosp?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
driverClass=com.mysql.cj.jdbc.Driver

2. 使用数据库连接池

public class TestDruid {
	public static void main(String[] args) throws Exception {
		Properties pro = new Properties();		 pro.load(TestDruid.class.getClassLoader().getResourceAsStream("druid.properties"));
		DataSource ds = DruidDataSourceFactory.createDataSource(pro);
		Connection conn = ds.getConnection();
		System.out.println(conn);
	}
}
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
username=root
password=123456
driverClassName=com.mysql.jdbc.Driver

initialSize=10
maxActive=20
maxWait=1000
filters=wall
  • 详细配置参数:
配置缺省说明
name配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:”DataSource-” + System.identityHashCode(this)
url连接数据库的url,不同数据库不一样。例如:mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username连接数据库的用户名
password连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/使用ConfigFilteropen in new window
driverClassName根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下)
initialSize0初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
maxActive8最大连接池数量
maxIdle8已经不再使用,配置了也没效果
minIdle最小连接池数量
maxWait获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
poolPreparedStatementsfalse是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
maxOpenPreparedStatements-1要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
validationQuery用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。
testOnBorrowtrue申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
testOnReturnfalse归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testWhileIdlefalse建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
timeBetweenEvictionRunsMillis有两个含义: 1)Destroy线程会检测连接的间隔时间2)testWhileIdle的判断依据,详细看testWhileIdle属性的说明
numTestsPerEvictionRun不再使用,一个DruidDataSource只支持一个EvictionRun
minEvictableIdleTimeMillis
connectionInitSqls物理连接初始化的时候执行的sql
exceptionSorter根据dbType自动识别 当数据库抛出一些不可恢复的异常时,抛弃连接
filters属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
proxyFilters类型是List,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系

3. Apache-DBUtils工具类:

commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。

MyBatis

1. 引入

		<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
		<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/atguigudb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印执行sql
    lazy-loading-enabled: true #开启延迟加载
  type-aliases-package: com.apple.demo.bean

2. Mybatis的增删改查:

注意
1、查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射关系
resultType:自动映射,用于属性名和表中字段名一致的情况
resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况
2、当查询的数据为多条时,不能使用实体类作为返回值,只能使用集合,否则会抛出异常TooManyResultsException;但是若查询的数据只有一条,可以使用实体类或集合作为返回值

3. Mybatis获取参数值的两种方式

建议参数的设置以 两种方式为主,一是实体类对象,二是使用注解命名参数

/**
     * mapper接口的不同参数类型,xml获取参数值:
     * 1.单个参数
     *      xml 以${} #{} 访问
     * 2.多个参数
     *      mybatis自动封装多个参数到map {arg0: v1,arg1:v2}或{param0:v1,param1:v2}
     *      xml以mybatis自动设置的键值获取参数
     *
     * 3.参数类型为map
     *      xml以自己设置的键值获取参数
     *
     * 4.参数是实体类类型
     *      实体类是属性和属性值
     *      xml以实体类的属性名获取属性值
     *
     * 5.使用@Param命名参数
     *      使用@Param("value")设置键值      mybatis设置键值的方式有两种,一是以value为键,二是以param0,param1,。。。
     *      xml以value为键获取参数值
     *
     *
     *  建议参数的设置以 两种方式为主,一是实体类对象,二是使用注解命名参数
     */

4. MyBatis的各种查询功能

/**
     * mybaits的各种查询功能
     *
     * 1. 若查出的数据只一条,
     *      a.实体类接收
     *      b.集合接收
     *      c.map集合
     * 2. 若查出的数据有多条,
     *      a.list集合接收
     *      b.map类型的list集合接收
     *      c.添加@Mapkey使用某个字段作为键,使用map接收
     *
     * MyBatis中设置了默认的类型别名
     *
     */

5. 特殊sql的执行

/**
	 * 特殊的sql查询
     * 1.模糊查询
     *      "%"#{}"%"
     * 2.批量删除
     *      int deleteMore(@Param("ids") String ids);
     *      delete from t_user where id in (${ids})
     * 3.动态表名
     *      表名作为参数 #{tableName}
     * 4.获取自增的主键
     *      插入语句的返回值是固定的,不能更改,所以主键要另寻存储的地方
     *      useGeneratedKeys="true" keyProperty="id"
     *      useGeneratedKeys: 设置当前标签中的sql使用了自增的主键
     *      keyProperty: 将自增的主键的值赋值给传输到映射文件中的参数的某个属性
     */

6. 自定义映射ResultMap

/**
     * 解决字段名和属性名不一致的情况:
     *  1. 为字段名起别名,保持和属性名的一致
     *          select id,emp_name empName,age,sex,email,did from t_emp
     *  2. 设置全局并配置,将_自动映射为驼峰
     *          map-underscore-to-camel-case: true
     *  3.通过resultMap 设置自定义的映射关系
     *     <resultMap id="empResultMap" type="com.apple.demo.bean.Emp">
     *         <id property="eid" column="eid"></id>
     *         <result property="empName" column="emp_name"></result>
     *         <result property="age" column="age"></result>
     *         <result property="sex" column="sex"></result>
     *         <result property="email" column="email"></result>
     *     </resultMap>
     *
     *  处理多对一的映射关系:
     *   1. 级联属性
     *         <result property="dept.did" column="did"></result>
     *         <result property="dept.deptName" column="dept_name"></result>
     *   2. association
     *         <association property="dept" javaType="com.apple.demo.bean.Dept">
     *             <id property="did" column="did"></id>
     *             <result property="deptName" column="dept_name"></result>
     *         </association>
     *   3. 分步查询
     *         <association property="dept"
     *                      select="com.apple.demo.dao.DeptMapper.getEmpAndDeptByStepTwo"
     *                      column="did">
     *         </association>
	 *
     *         分步查询的优点是可以实现延迟加载:
     *              lazy-loading-enabled: true
     *              emp.getEmpName() 只是用第一步的sql,不会加载其他的sql
     *
     *                      fetchType="lazy | eager" 延迟加载 开启 | 关闭
     *
     *
     * 处理多对一的映射关系:
     *   1. collection
     *         <collection property="emps" ofType="com.apple.demo.bean.Emp">
     *             <id property="eid" column="eid"></id>
     *             <result property="empName" column="emp_name"></result>
     *             <result property="age" column="age"></result>
     *             <result property="sex" column="sex"></result>
     *             <result property="email" column="email"></result>
     *         </collection>
     *   2. 分布查询
     *        <collection property="emps"
     *                     select="com.apple.demo.dao.EmpMapper.getDeptAndEmpByStepTwo"
     *                     column="did">
     *             <id property="eid" column="eid"></id>
     *             <result property="empName" column="emp_name"></result>
     *             <result property="age" column="age"></result>
     *             <result property="sex" column="sex"></result>
     *             <result property="email" column="email"></result>
     *         </collection>
     */

7. 动态sql

/**
     * 动态sql:
     *  1. if: 根据标签中test属性所对应的表达式决定标签中的内容是否需要拼接到sql中
     *     <select id="getEmpByCondition" resultType="com.apple.demo.bean.Emp">
     *         select * from t_emp where 1=1
     *         <if test="empName != null and empName != ''">
     *             and emp_name = @{empName}
     *         </if>
     *         <if test="age != null and age != ''">
     *             and age = @{age}
     *         </if>
     *         <if test="sex != null and sex != ''">
     *             and sex = @{sex}
     *         </if>
     *         <if test="email != null and email != ''">
     *             and email = @{email}
     *         </if>
     *     </select>
     *  2. where: 当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and或or去掉,
     *            当where标签中没有内容时,此时的where标签没有任何效果
     *            注意:where标签不能去掉内容后面多余的and 或 or
     *        <where>
     *             <if test="empName != null and empName != ''">
     *                 and emp_name = @{empName}
     *             </if>
     *             <if test="age != null and age != ''">
     *                 and age = @{age}
     *             </if>
     *         </where>
     *
     *  3. trim:
     *      若标签中有内容时:
     *      prefix | suffix : 将trim标签中内容前面或后面添加指定内容
     *      prefixOverrides | suffixOverrides : 将trim标签中内容前面或后面去掉指定内容
     *      若没有内容,没有任何效果
     *  4. choose,when,otherwise 相当于 if。。。else if.... else...
     *      <choose>
     *          <when test="">
     *              case1
     *          </when>
     *          <when test="">
     *              case2
     *          </when>
     *          <when test="">
     *              case3
     *          </when>
     *          <otherwise>
     *              else case
     *          </otherwise>
     *      </choose>
     *
     *  5. foreach:
     *     批量删除:
     *     <delete id="deleteMoreByArray">
     *         delete from t_emp where eid in
     *
     *         <foreach collection="eids" item="eid" separator="," open="(" close=")">
     *             #{eid}
     *         </foreach>
     *
     *     </delete>
     *
     *     <delete id="deleteMoreByArray">
     *         delete from t_emp where
     *
     *         <foreach collection="eids" item="eid" separator="or">
     *             eid = #{eid}
     *         </foreach>
     *
     *     </delete>
     *
     *     批量添加:
     *     <insert id="insertMoreByList">
     *         insert into t_emp values
     *         <foreach collection="emps" item="emp" separator=",">
     *             (null,#{emp.empName},#{emp.age},#{amp.sex},#{emp.email},null)
     *         </foreach>
     *     </insert>
     *
     *   6. sql标签:
     *    <sql id="empColumns">eid,ename,age,sex,email</sql>
     *    <include refid="empColumns"></include>
     *
     *
     */

8.Mybatis的缓存

一级缓存

一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问

二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被
缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取

缓存查询顺序

  • 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
  • 如果二级缓存没有命中,再查询一级缓存
  • 如果一级缓存也没有命中,则查询数据库
  • SqlSession关闭之后,一级缓存中的数据会写入二级缓存

其他

xml配置文件参考

log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">  
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">  
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">  
        <layout class="org.apache.log4j.PatternLayout">  
            <param name="ConversionPattern" value="%5p [%t] %m%n" />  
        </layout>  
    </appender>   
     <logger name="org.fkit.mapper">  
        <level value="DEBUG" />  
    </logger> 
    <root>  
        <level value="ERROR" />  
        <appender-ref ref="STDOUT" />  
    </root>  
</log4j:configuration>

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">
  <!--  XML 配置文件包含对 MyBatis 系统的核心设置 -->
<configuration>
	<properties resource="db.properties"/>
	<!-- 指定 MyBatis 所用日志的具体实现 -->
	<settings>
		<setting name="logImpl" value="LOG4J"/>
		<!-- 开启二级缓存 -->
		<setting name="cacheEnabled" value="true"/>
	</settings>
	<environments default="mysql">
	<!-- 环境配置,即连接的数据库。 -->
    <environment id="mysql">
    <!--  指定事务管理类型,type="JDBC"指直接简单使用了JDBC的提交和回滚设置 -->
      <transactionManager type="JDBC"/>
      <!--  dataSource指数据源配置,POOLED是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>
  <!-- mappers告诉了MyBatis去哪里找持久化类的映射文件 -->
  <mappers>
  	<mapper class="org.fkit.mapper.UserMapper"/>
  </mappers>
</configuration>

MBG代码生成

MyBatis Generator(MBG)是MyBatis MyBatis 和iBATIS的代码生成器。它将为所有版本的MyBatis以及版本2.2.0之后的iBATIS版本生成代码。它将内省数据库表(或许多表),并将生成可用于访问表的工件。这减少了设置对象和配置文件以与数据库表交互的初始麻烦。MBG寻求对简单CRUD(创建,检索,更新,删除)的大部分数据库操作产生重大影响。您仍然需要为连接查询或存储过程手动编写SQL和对象代码。

MyBatis Generator将生成:

与表结构匹配的Java POJO。这可能包括:
一个匹配表的主键的类(如果有主键)
一个匹配表的非主键字段的类(BLOB字段除外)
包含表的BLOB字段的类(如果表具有BLOB字段)
用于启用动态选择,更新和删除的类
这些类之间存在适当的继承关系。请注意,生成器可以配置为生成不同类型的POJO层次结构 - 例如,如果您愿意,可以选择为每个表生成单个域对象。

MyBatis / iBATIS兼容的SQL Map XML文件。MBG在配置中的每个表上为简单的CRUD函数生成SQL。生成的SQL语句包括:
插入
按主键更新
通过示例更新(使用动态where子句)
按主键删除
按示例删除(使用动态where子句)
按主键选择
按示例选择(使用动态where子句)
以身作则
根据表的结构,这些语句有不同的变体(例如,如果表没有主键,则MBG不会通过主键功能生成更新)。

适当使用上述对象的Java客户端类。Java客户端类的生成是可选的。MBG将为MyBatis 3.x生成以下类型的Java客户端:
适用于MyBatis 3.x映射器基础结构的映射器接口
MBG将为iBATIS 2.x生成以下类型的Java客户端:
符合Spring框架的DAO
仅使用iBATIS SQL映射API的DAO。这些DAO可以生成两种:通过构造函数或setter注入提供SqlMapClient。
符合iBATIS DAO框架的DAO(iBATIS的可选部分,现在不推荐使用此框架,我们建议您使用Spring框架)
MyBatis生成器设计为在迭代开发环境中运行良好,并且可以作为Ant任务或Maven插件包含在连续构建环境中。迭代运行MBG时需要注意的重要事项包括:

如果存在与新生成的XML文件同名的现有文件,MBG将自动合并XML文件。MBG不会覆盖您对其生成的XML文件所做的任何自定义更改。您可以反复运行它,而不必担心会丢失对XML的自定义更改。MBG将替换先前运行中生成的任何XML元素。
MBG 不会合并Java文件,它可以覆盖现有文件或使用不同的唯一名称保存新生成的文件。如果对生成的Java文件进行更改并以迭代方式运行MBG,则必须手动合并更改。当作为Eclipse 插件运行时 ,MBG可以自动合并Java文件。

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.5