简介
- MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
- mybatis与hibernate不同
不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。 - Mybatis学习门槛低,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
jdbc编程问题
- 频繁创建、关闭数据连接,太消耗资源
- Sql语句存在硬编码,不利于维护
- Sql参数设置硬编码,不利于维护
- 结果集获取与遍历复杂,存在硬编码,不利于维护,期望能够查询后返回一个java对象
MyBatis
- 使用数据库连接池。
- 将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
- Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
- Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。
JDBC代码
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
// 定义sql语句 ?表示占位符
String sql = "select * from user where username = ?";
// 获取预处理statement
preparedStatement = connection.prepareStatement(sql);
// 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "王五");
// 向数据库发出sql执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
// 遍历查询结果集
while (resultSet.next()) {
System.out.println(resultSet.getString("id") + " " + resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放资源
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
{ }和${ }
- #{}:占位符,可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
- \${}:拼接sql串,将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, \${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,\${}括号中只能是value。
SqlMapConfig.xml配置文件
-
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性) settings(全局配置参数) typeAliases(类型别名) typeHandlers(类型处理器) objectFactory(对象工厂) plugins(插件) environments(环境集合属性对象) environment(环境子属性对象) transactionManager(事务管理) dataSource(数据源) mappers(映射器)
-
自定义别名:
<typeAliases> <!-- 单个别名定义 --> <typeAlias alias="user" type="cn.mybatis.pojo.User" /> <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) --> <package name="cn.mybatis.pojo" /> <package name="其它包" /> </typeAliases>
-
mappers(映射器)
使用相对于类路径的资源
<mapper resource="sqlmap/User.xml" />
使用mapper接口类路径。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
<mapper class="cn.mybatis.mapper.UserMapper"/>
注册指定包下的所有mapper接口。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
<package name="cn.mybatis.mapper"/>
输出映射
<!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo -->
<!-- id:设置ResultMap的id -->
<resultMap type="order" id="orderResultMap">
<!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id -->
<!-- property:主键在pojo中的属性名 -->
<!-- column:主键在数据库中的列名 -->
<id property="id" column="id" />
<!-- 定义普通属性 -->
<result property="userId" column="user_id" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
<association property="author" javaType="Author">
<result property="username" column="author_username"/>
</association>
<collection property="posts" ofType="Post">
<result property="subject" column="post_subject"/>
</collection>
<discriminator javaType="int" column="vehicle_type">
<case value="1" resultType="carResult">
<result property="doorCount" column="door_count" />
</case>
<case value="2" resultType="truckResult">
<result property="boxSize" column="box_size" />
<result property="extendedCab" column="extended_cab" />
</case>
</discriminator>
</resultMap>
<!-- 查询所有的订单数据 -->
<select id="queryOrderAll" resultMap="orderResultMap">
SELECT id, user_id,
number,
createtime, note FROM `order`
</select>
动态sql
if语句
if条件判断语句可以直接执行对象的方法
<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
SELECT id, username, birthday, sex, address FROM `user`
WHERE 1=1
<if test="sex != null and sex != ''">
AND sex = #{sex}
</if>
<if test="username != null and username != ''">
AND username LIKE
'%${username}%'
</if>
</select>
数字类型
gt 对应 >
gte 对应 >=
lt 对应 <(会报错 相关联的 "test" 属性值不能包含 '<' 字符)
lte 对应 <=(会报错 相关联的 "test" 属性值不能包含 '<' 字符)
<if test="id != null">
<if test='id != null and id > 28'>
<if test='id != null and id gt 28'>
字符串
eq 对应 ==
neq 对应 !=
<if test="name != null and name.trim() != ''">
<if test="name != null and name.indexOf('ji') == 0"> <!-- 是否以什么开头 -->
<if test="name != null and name.indexOf('ji') >= 0"> <!-- 是否包含某字符 -->
<if test="name != null and name.lastIndexOf('ji') > 0"> <!-- 是否以什么结尾 -->
<if test="name != null and 'hello' == name">
<if test="username != null and 'hello' eq name">
<if test="name != null and 'hello'.toString() == name.toString()"> <!-- name非字符串时 -->
<if test="'xiaohong' eq name or 'xiao' eq name ">
list
<if test="list != null and list.size()>0">
数组
<if test="ids!=null and ids.length>0">
时间
<if test="releaseDateStart != null and releaseDateEnd != null ">
sql条件判断
UPDATE tb_volunteer
SET honor_level = (
CASE
<![CDATA[WHEN score < 5001 THEN 0]]>
<![CDATA[WHEN score > 5000 AND score < 10001 THEN 1]]>
<![CDATA[WHEN score > 10000 AND score < 15001 THEN 2]]>
END );
where语句
<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
SELECT id, username, birthday, sex, address FROM `user`
<!-- where标签可以自动添加where,同时处理sql语句中第一个and关键字 -->
<where>
<if test="sex != null">
AND sex = #{sex}
</if>
<if test="username != null and username != ''">
AND username LIKE
'%${username}%'
</if>
</where>
</select>
-
sql片段
<!-- 根据条件查询用户 --> <select id="queryUserByWhere" parameterType="user" resultType="user"> <!-- SELECT id, username, birthday, sex, address FROM `user` --> <!-- 使用include标签加载sql片段;refid是sql片段id --> SELECT <include refid="userFields" /> FROM `user` <!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 --> <where> <if test="sex != null"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </where> </select> <!-- 声明sql片段 --> <sql id="userFields"> id, username, birthday, sex, address </sql>
-
foreach标签
<!-- 根据ids查询用户 --> <select id="queryUserByIds" parameterType="queryVo" resultType="user"> SELECT * FROM `user` <where> <!-- foreach标签,进行遍历 --> <!-- collection:遍历的集合,这里是QueryVo的ids属性 --> <!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 --> <!-- open:在前面添加的sql片段 --> <!-- close:在结尾处添加的sql片段 --> <!-- separator:指定遍历的元素之间使用的分隔符 --> <foreach collection="ids" item="item" open="id IN (" close=")" separator=","> #{item} </foreach> </where> </select>
like语句
name LIKE CONCAT('%',#{keyword},'%')
foreach语句
<!--list -->
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
<!--array数组-->
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
<!--封装到map中,dicts为map中的key-->
<foreach collection ="dicts" item="dict" index= "index" separator =",">
插入语句
插入另一张表的数据
insert into 表一(字段一,字段二) select 字段一,字段二 from 表二;
批量插入
<insert id="batchInserDictData" parameterType="map">
INSERT INTO tb_volunteer_dict_data ( dict_id, dict_label, dict_value )
VALUES
<foreach collection ="list" item="dict" index= "index" separator =",">
(#{dictTypeId}, #{dict.dictLabel},#{dict.dictValue} )
</foreach>
</insert>
批量插入(返回id)
<insert id="saveDictType" parameterType="list" useGeneratedKeys="true" keyProperty="dictTypeId">
INSERT INTO tb_type ( dict_name, creator, create_date)
VALUES
<foreach collection ="list" item="dict" index= "index" separator ="," >
<if test="dict.dictName != null and dict.dictName.trim() != ''">
(#{dict.dictName}, #{dict.creator}, #{dict.createDate})
</if>
</foreach>;
</insert>
单个插入(返回id)
<insert id="save" parameterType="map" useGeneratedKeys="true" keyProperty="dto.templateId">
INSERT INTO tb_template ( template_name, template_status, org_id)
VALUES (#{dto.templateName}, #{dto.templateStatus}, #{orgId});
</insert>
mysql死锁错误
代码调试的时候出现错误
SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restart
可以用下面三张表来查原因:
innodb_trx ## 当前运行的所有事务
innodb_locks ## 当前出现的锁
innodb_lock_waits ## 锁等待的对应关系
解决步骤
查找到为提交事务的数据,kill此线程即可
select * from information_schema.innodb_trx;
-- trx_mysql_thread_id 即为该进程
kill 1544;
备注
参考:https://blog.csdn.net/flysnow...
参考:https://blog.csdn.net/zc47423...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。