Mybatis代码记录
初始化Mybatis项目
新建maven工程,导入依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
IDEA中database的设置





小tips
可以直接在idea中的控制台输入sql指令,非常方便


generate …可以生成实体类
go to scripts Directory可以配置生成实体类的模板,下面是我的部分配置,只需要改一部分就行了

附上修改的代码
//修改包名
packageName = "com.lingxi.pojo;"
.
.
.
def generate(out, className, fields) {
out.println "package $packageName"
out.println ""
//导入lombok包、把mysql的时间改为date
out.println "import lombok.Data;"
out.println "import java.util.Date;"
//加入注解
out.println "@Data"
out.println "public class $className {"
out.println ""
fields.each() {
if (it.annos != "") out.println " ${it.annos}"
out.println " private ${it.type} ${it.name};"
}
out.println ""
//注释原来的set和get
/* fields.each() {
out.println ""
out.println " public $
生成效果

alt+回车解决问题,自动导包到项目路径下
备注,还要在idea的setting插件中心下载个插件神器,方便在xml和接口中跳转
原(下架了):easy mybatis
改:mybatisx:可以快速在xml和接口跳转,生成xml配置文件
照猫画虎,模仿官网
基本配置
学mybatis一定要看官网
第一步,配置mybatis.config
这里暂时先直接写死,后面有更优方案
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/4032?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--这里是可以放很多东西的,预留-->
</configuration>
测试类,以下是通用部分
//@BeforeClass @Before @After @AfterClass
private static SqlSessionFactory sqlSessionFactory = null;
private static InputStream inputStream = null;
private SqlSession sqlSession = null;
/**
* 在开始创建类的时候运行这个方法
*/
@BeforeClass
public static void init() {
//1.加载mybatis 配置文件:核心 和 映射文件
String resource = "mybatis-config.xml";
//读取配置文件(注意导入正确的包): 方式一:
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
//2.创建sqlSessionFactory(读取流)
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
/**
* 在完成这个类的时候调用方法
*/
@AfterClass
public static void destroy() {
sqlSessionFactory = null;
//6.关闭流
if (null != inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 在开始方法前调用此方法
*/
@Before
public void openSession() {
//3.创建sqlSession
sqlSession = sqlSessionFactory.openSession();
}
/**
* 在调用方法后调用此方法
*/
@After
public void closeSqlSession() {
//5.关闭sqlSession
if (null != sqlSession) {
sqlSession.commit();
//关闭sqlSession
sqlSession.close();
}
}
开始准备Mapper的接口和xml配置文件
建议先建立最简单的xml和接口,因为有mybaits插件的原因,可以节省很多工作量
Mapper.xml模板
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lingxi.mapper.SysuserMapper">
<!-- namespace :代表一个映射文件,可以随便写,
但是我们实际开发中我们写 Mapper接口的权限定类名
-->
<!-- id: 唯一标识 ,id和namespace 联合起来可以定位到具体的sql语句 -->
</mapper>
public interface SysuserMapper {
}
这时候写好接口方法,插件会提醒

写sql完事

不自信的话可以先在database的控制台里面敲一下试试
写好sql、接口方法、测试方法后,别忘了在mybaits-config里面注册mapper
<mappers>
<mapper resource="com/lingxi/mapper/SysuserMapper.xml"/>
</mappers>
CRUD(XML配置实现)
个人认为编写顺序
接口方法 → xml配置写sql → 测试方法
核心代码太简单,而且要复制几个文件,懒得写了
但是提一个点,sqlsession执行方法的两种方法(推荐第二种)
// 通过完全限定名+方法名实现
List<Sysuser> sysusers = sqlSession.selectList("com.lingxi.mapper.SysuserMapper.selectAllUser");
// 通过调用接口实现
/* SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
List<Sysuser> sysusers = mapper.selectAllUser();*/
// mapper是sqlSession生成的动态代理对象
CRUD(注解实现,推荐使用简单的)
@Select("select * from sysrole")
List<Sysrole> getAllrole();
@Insert("insert into sysrole (rname,rdec,create_time,update_time) values (#{rname},#{rdec},#{createTime},#{updateTime})")
int addRole(Sysrole sysrole);
@Delete("delete from sysrole where rid=#{id}")
int delRole(int id);
@Update("update sysrole set rname=#{rname},rdec=#{rdec},create_time=#{createTime},update_time=#{updateTime} where rid=#{rid}")
int updateRole(Sysrole sysrole);
@Select("select * from sysrole where rid=#{id}")
Sysrole selectOneByRid(int id);
增强功能
新增用户,返回自增ID
废话少说,直接上代码
接口
/**
* 新增用户,并且拿到返回的自增主键,返回到传过来的user中
* @param sysuser
* @return
*/
int addUserAndGetKey(Sysuser sysuser);
xml配置
<insert id="addUserAndGetKey" keyProperty="uid" useGeneratedKeys="true">
insert into sysuser (uname, upwd, uemail, phone, create_time, update_time, deleted, rid) values (#{uname},#{ upwd},#{ uemail},#{ phone},#{ createTime},#{ updateTime},#{ deleted},#{ rid});
</insert>
测试方法
@Test
public void test_addUserAndGetKey() {
SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
Sysuser sysuser = new Sysuser();
sysuser.setUname("自增用户");
sysuser.setUpwd("123");
int i = mapper.addUserAndGetKey(sysuser);
System.out.println("影响行数"+i);
System.out.println("自增主键"+sysuser.getUid());
}
结果

模糊查询
<select id="selectLikeUser" resultType="com.lingxi.pojo.Sysuser">
select * from sysuser where uname like '%' #{uname} '%';
</select>
注意
-
'%' #{uname} '%'之间是有空格的 -
/**/用在sql之间会报错,是那种sql语句就不能在里面报错,之前不信,现在信了

-
可以使用双引号,但不建议
多参数查询
使用注释和默认多参数名称
接口
List<Sysuser> selectUserByMultiParams(@Param("name") String name, @Param("pwd")String pwd);
xml
<select id="selectUserByMultiParams" resultType="com.lingxi.pojo.Sysuser">
select * from sysuser where uname like '%${name}%' and upwd=#{pwd};
</select>
或者不使用@param
使用arg1, arg0, param1, param2
<select id="selectUserByMultiParams" resultType="com.lingxi.pojo.Sysuser">
select * from sysuser where uname like '%${param1}%' and upwd=#{param2};
</select>
使用Map
接口
List<Sysuser> selectUserByMap(Map map);
xml
<select id="selectUserByMap" resultType="com.lingxi.pojo.Sysuser">
select * from sysuser where uname like '%${name}%' and upwd=#{pwd};
</select>
测试方法
@Test
public void test_selectUserByMap() {
SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
HashMap<String, String> map = new HashMap<>();
map.put("name", "张");
map.put("pwd", "123456");
List<Sysuser> sysuserList = mapper.selectUserByMap(map);
sysuserList.forEach(System.out::println);
}
使用自定义实体类
极其lowB,不建议使用,这个原理就和表传对应的实体类是一个原理
配置日志
加入依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
配置文件log4j.properties
### \u8BBE\u7F6E###
log4j.rootLogger = debug,stdout,D,E
### \u8F93\u51FA\u4FE1\u606F\u5230\u63A7\u5236\u62AC ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### \u8F93\u51FADEBUG \u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7\u5230=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### \u8F93\u51FAERROR \u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7\u5230=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =D://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
配置数据库properties
先写好properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/4032?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC
jdbc.username=root
jdbc.password=root
为什么要写jdbc前缀呢?防止冲突
另外注意properties不需要转义字符
mybatis的配置文件需要改两个地方
加上properties的标签,注意这个是有顺序的
<properties resource="db.properties"/>
改好环境配置
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
驼峰命名
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
设置别名
<!--设置别名-->
<typeAliases>
<!--单个实体类设置别名-->
<typeAlias type="com.lingxi.pojo.Sysuser" alias="User"/>
<!--包扫描方法,全局配置,默认别名为类名-->
<package name="com.lingxi.pojo"/>
</typeAliases>
设置Mapper映射
<mappers>
<!--第一种方式:单独配置xml文件-->
<mapper resource="com/lingxi/mapper/SysuserMapper.xml"/>
<!--第二种方式:单独配置类名-->
<mapper class="com.lingxi.mapper.SysroleMapper"/>
<!--第三种方式:全局配置,包扫描-->
<package name="com.lingxi.mapper"/>
</mappers>
复杂功能
一对一(对象中包含对象)
其实重点是在xml中的配置,先介绍一下resultMap的概念,resultMap实际上可以解决数据库字段名与实体类不对应的问题
<select id="selectUserBySort" resultMap="sortMap">
select * from sysuser order by ${sortedColumn} ${sorted};
</select>
<!--resultMap可以解决数据库中字段与实体类的属性不一致的问题
resultMap的id要对应
resultMap和resultType只能配置一个
-->
<resultMap id="sortMap" type="Sysuser">
<!--id必须配置,其他与实体类一致的可以不配置-->
<id column="uid" property="uid"/>
<result column="create_time" property="createTime"/>
</resultMap>
那么,就是将resultMap的功能再次升级
<select id="getUserByIdContainRole" resultMap="UserContainRole">
select * from sysuser where uid=#{id}
</select>
<resultMap id="UserContainRole" type="Sysuser">
<id property="uid" column="uid"/>
<association property="sysrole" javaType="com.lingxi.pojo.Sysrole"
select="com.lingxi.mapper.SysroleMapper.selectOneByRid" column="rid"/>
</resultMap>
这其中有几点我要解释一下
- resultMap中id是必须要配置的,实体类中的id要与数据库中表的id对应
- association代表这个列的联系
- javaType表示这个联系会最后转成java的什么类型
- select表示这个列后续的查找操作,称之为子查询,这里是引用了一个方法
- column是表示将这个列作为需要的参数传入select指向的方法之中
一对多(一个实体类内包含集合)
方法一:利用sql进行查询,需要处理列
xml配置
<select id="getRoleContainUser" resultMap="roleContainUser">
select sr.* ,su.uid,su.uname,su.upwd,su.uemail,su.phone,su.deleted,su.rid su_rid,su.create_time su_create_time,su.update_time su_update_time
from sysrole sr ,sysuser su
where sr.rid = su.rid and sr.rid = #{rid}
</select>
<resultMap id="roleContainUser" type="com.lingxi.pojo.Sysrole">
<id column="rid" property="rid"></id>
<result column="rname" property="rname"></result>
<result column="create_time" property="createTime"></result>
<result column="update_time" property="updateTime"></result>
<result column="rdec" property="rdec"></result>
<collection property="sysusers" ofType="com.lingxi.pojo.Sysuser">
<id column="uid" property="uid"></id>
<result column="uname" property="uname"></result>
<result column="upwd" property="upwd"></result>
<result column="uemail" property="uemail"></result>
<result column="create_time" property="createTime"></result>
<result column="update_time" property="updateTime"></result>
<result column="phone" property="phone"></result>
<result column="deleted" property="deleted"></result>
<result column="su_rid" property="rid"></result>
</collection>
</resultMap>
解释:
这个方法其实是直接通过sql进行查询,将查询的结果直接每个列都映射到相应实体类中,下面来解释标签的作用
- collection指的是集合,也就是这个标签返回回来的类型必然是个集合,因为是collection,所以里面可以有多个result标签,对应着相应实体类的值
- ofType表示它是一个实体类中的实体类
- property对应的sysusers就是List
,所以直接就映射回去了 - result就是普通的值,就是普通的列对应对象或者基本类型这种
方法二:利用子查询
xml配置
<select id="getRoleContainUserBy2" resultMap="roleContainUser2">
select * from sysrole where rid=#{rid}
</select>
<resultMap id="roleContainUser2" type="com.lingxi.pojo.Sysrole">
<id column="rid" property="rid"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
<!--这里有两种写法-->
<!--第一种,建立联系-->
<association property="sysusers" javaType="arraylist" column="rid" select="com.lingxi.mapper.SysuserMapper.getUserByRid"/>
<!--第二种,建立集合关系-->
<collection property="sysusers" ofType="com.lingxi.pojo.Sysuser" select="com.lingxi.mapper.SysuserMapper.getUserByRid" column="rid"/>
</resultMap>
<select id="getUserByRid" resultType="com.lingxi.pojo.Sysuser">
select *from sysuser where rid=#{rid};
</select>
解释:其实感觉没啥好解释的,但是可以说一下流程
- 找到需要的信息
- 根据信息中的关键字段,继续查找
- 将关键字段查找到的信息再次映射回类型中
懒加载(了解)
mybaits核心配置xml添加setting
<setting name="lazyLoadingEnabled" value="true"></setting>


小记:
生效场景:mybatis中的延迟加载仅在有二次查询的场景下生效.
延迟加载目的:减少无效的数据库查询操作,提高响应的效率。
延迟加载应用:分页,树形结构数据,前端图片的延迟加载
除了toString 以外,只要是没有使用到sysrole ,就不会触发二次查询
缓存
cache:减少数据库的重复查询操作.基于内存把第一次查询的结果保存的缓存对象中,当后续查询时,先查询缓存,缓存中有则返回;缓存中没有则查询数据库,并把查询结果放缓存。(核心,写代码的逻辑)
ehcache 占用web服务器的内存(一般不用)
memercache,redis 独立部署的缓存
mybatis的缓存分为两级:
session级别缓存(一级缓存):默认开启 同一个sqlSession
factory级别缓存(二级缓存):默认未开启. 同一个sqlSessionFactory
一级缓存:
在web系统中,每次用户请求,后端开启sqlsession,查询完毕,session关闭.
默认开启,只在一次sqlsession中生效


二级缓存:
不同的sqlsession进行操作,可以命中缓存
核心配置文件添加设置:
<setting name="cacheEnabled" value="true"></setting>
映射配置文件:
缓存策略
<!--只对当前namespace下的所有查询全部生效,-->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
<!--可以再select中加usecache禁用二级缓存-->
<select id="selectOneById" resultType="com.lingxi.pojo.Sysuser" useCache="false">
select * from sysuser where uid=#{id}
</select>
<!--可以在update,delete中使用flushcache强制清空缓存
清空原因:数据变化了
-->
<update id="updateUser" flushCache="true">
update sysuser set uname = #{uname},upwd = #{upwd}where uid=#{uid};
</update>
- FIFO:先进先出
- 缓存大小:512个引用
- 缓存间隔:60000毫秒,一分钟刷新一次
- 只读

失去一级缓存时会查询两次,且日志也不会报缓存命中率,这个懒得截图了,随便改个配置都会导致二级缓存失效
sql标签
开发中一般是不使用*作为查询所有列的,所以推荐使用sql标签,需要在mapper的配置文件中添加如下
<sql id="allColumn">
uid , uname, upwd, uemail, phone, create_time, update_time, deleted, rid
</sql>
然后再查询标签中引用
<select id="selectAllUser" resultType="com.lingxi.pojo.Sysuser">
select
<include refid="allColumn"/>
from sysuser;
</select>
查询结果

tips:idea中如果配置了sql方言可能会报错,修改如下

动态sql
动态的生成SQL语句,防止条件不足和减轻代码量
where标签
其实就是把where标签里面的第一个and的标签去掉,其实不用where标签也可以,使用where1=1也可以但是不符合规范
<select id="getUserWhere" resultType="com.lingxi.pojo.Sysuser">
select
<include refid="allColumn"/>
from sysuser
<where>
<if test="uname!=null and uname!=''">
and uname like '%' #{uname} '%'
</if>
<if test="upwd!=null and upwd!=''">
and upwd = '%' #{upwd} '%'
</if>
</where>
set标签
更新的字段有些不更新,就可以去掉逗号,起到只修改指定字段的效果
<update id="updateUser" flushCache="true">
update sysuser
<set>
<if test="uname!=null and uname!=''">
,uname = #{uname}
</if>
<if test="upwd!=null and upwd!=''">
,upwd = #{upwd}
</if>
</set>
where uid = #{uid};
</update>
foreach标签
在传入多个数值时,用于拼接sql
<delete id="delUsers">
delete from sysuser
where uid in
<foreach collection="list" item="uid" separator="," open="(" close=")">
#{uid}
</foreach>
</delete>
foreach内部解释:
- collection支持collection(list)和array
- item就是代指内部的项目的每个名字,我感觉有点类似于java中的for增强即[for(item in items)]
- 也可以通过@Param的注释在collection中传递自定义名称
批量插入用户,foreach配合对象使用
<insert id="batchAddUsers">
insert into sysuser (uname,upwd) values
<foreach collection="list" separator="," item="user" >
(#{user.uname},#{user.upwd} )
</foreach>
</insert>
注意这里不要加open和close,语法问题,貌似mybaits会自己添加( )
本文来自博客园,作者:凌曦的博客,转载请注明原文链接:https://www.cnblogs.com/lingxi307/articles/15907895.html

浙公网安备 33010602011771号