MyBatis基础用法总结
使用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/使用ConfigFilter | |
driverClassName | 根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下) | |
initialSize | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
maxActive | 8 | 最大连接池数量 |
maxIdle | 8 | 已经不再使用,配置了也没效果 |
minIdle | 最小连接池数量 | |
maxWait | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 | |
poolPreparedStatements | false | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 |
maxOpenPreparedStatements | -1 | 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 |
validationQuery | 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。 | |
testOnBorrow | true | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle | false | 建议配置为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文件。