参考网址 :
mybatis中文网
mybatis 多表查询 @Select 注解
mapper接口
public interface UserMapper extends BaseMapper<User> {
。。。。
}
service 实现 IService 接口 ,impl继承 ServiceImpl 实现 service 接口
public interface 自定义Service extends IService<自定义实体bean> {
。。。
}
/**
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
。。。。
}
*/
public class 自定义ServiceImpl extends ServiceImpl<自定义Mapper, 自定义实体bean> implements 自定义Service {
。。。。
}
@Select 注解
@Select 动态参数
@Select({"<script> SELECT dir.* FROM GE_DIRECTORY dir INNER JOIN GE_PRODUCT_CORRELATION co ON dir.eid=co.RECOMMENDPRODUCT " +
"<when test='businessarea!=null and businessarea!=\"\" '>"+
" and dir.BUSINESSAREA=#{businessarea} " +
"</when>" +
"<when test='businessarea!=null and businessarea!=\"\" '>"+
" and dir.language=#{language} " +
"</when>" +
"<when test='productEid!=null and productEid!=\"\" '>"+
" and co.RECOMMENDPRODUCT=#{productEid} " +
"</when>" +
" </script>"})
List<GeDirectory> findAllRecommend(@Param("language") String language,@Param("businessarea") String businessarea,@Param("productEid") String productEid);
xml 动态sql
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<where>
<if test="clausecode!=null and clausecode != '' and clausecode.length > 0" >
and clausecode=#{clausecode}
</if>
<if test="validind!=null and validind != '' and validind.length > 0" >
and validind=#{validind}
</if>
<if test="language!=null and language != '' and language.length > 0">
and language=#{language}
</if>
</where>
select
<include refid="Base_Column_List" />
from ge_clause
<trim prefix="where" suffixOverrides="and">
<if test="clausecode!=null and clausecode != '' and clausecode.length > 0" >
clausecode=#{clausecode} and
</if>
<if test="validind!=null and validind != '' and validind.length > 0" >
validind=#{validind} and
</if>
<if test="language!=null and language != '' and language.length > 0">
language=#{language}
</if>
</trim>
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
Insert 语句
单个插入
<insert id="insert" parameterType="类名" >
insert into 数据库名 (数据库列字段)
values (#{对象属性}。。。。)
</insert>
批量插入
在foreach循环中一定要加上 item的变量名,在foreach标签中一定要使用 变量.属性
<!--批量插入-->
<insert id="batchInsert" parameterType="java.util.List">
insert into 数据库名 (数据库列字段)
values
<foreach collection="list" item="变量" index="index" separator=",">
(#{变量.属性) <!--一定要加上 item 中的 变量-->
</foreach>
</insert>
Delete 语句
@Delete("delete from ge_authority where authorityid='${authorityid}'")
boolean deleteAuthorityById(@Param("authorityid")String authorityid);
@Delete("delete from ge_role where roleid='${roleid}'")
void deleteRole(@Param("roleid")String roleid);
Update 语句
@Update("update ge_authority set authorityname = #{authorityname},authoritytype = #{authoritytype} , authoritydesp = #{authoritydesp}, authoritylink = #{authoritylink},authorityorder =#{authorityorder}, " +
"ismenu = #{ismenu},opentype =#{opentype},authoritytname=#{authoritytname},authorityename=#{authorityename} where authorityid = #{authorityid}")
void updateAuthority(GeAuthority geAuthority);
@Update("update `ge_webflowpageelement` set `STATUS`=1 WHERE COREPRODUCTCODE=#{coreproductcode} and ELEMENTCODE=#{productInfo} ")
void updateByElement(@Param("coreproductcode") String coreproductcode, @Param("productInfo") String productInfo);
1、在已有类中添加新属性,需添加注解@TableField(exist = false),否则mybatis-plus封装的方法会报错
在传统的crud中,我们查询的结果可能并不是我们需要传递给前端的数据,我们可能需要添加一些属性,再将结果返回给前端页面。比如我们再查询的时候需要查询关联子表,但是与数据库相对应的bean对象并没有这种children或者list属性承接对象,再这种时候要么新建一个类,要么再原有的bean对象上进行修改。
在原有bean对象上进行修改,关联查询自定义字段,需要使用注解@TableField(exist=false),即该条属性表示数据库表中不存在的,即mybatis-plus封装方法中sql语句不会使用此字段。自定义中可以使用。
2、自动填充
项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作:
(1)数据库表中添加自动填充字段
在User表中添加datetime类型的新的字段 create_time、update_time
(2)实体上添加注解
@Data
public class User {
......
@TableField(fill = FieldFill.INSERT)
private Date createTime;
//@TableField(fill = FieldFill.UPDATE)
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
(3)实现元对象处理器接口
注意:不要忘记添加 @Component 注解
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MyMetaObjectHandler.class);
@Override
public void insertFill(MetaObject metaObject) {
LOGGER.info("start insert fill ....");
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
LOGGER.info("start update fill ....");
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
3、错误 Duplicate entry ‘’ for key ‘PRIMARY’
### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '' for key 'PRIMARY'
### The error occurred while setting parameters
。。。。。。。。。。。。。。。
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '' for key 'PRIMARY'
; Duplicate entry '' for key 'PRIMARY'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '' for key 'PRIMARY'
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:243)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
问题分析 :
xml批量插入会导致主键无法生成。
解决办法:这里推荐 —调用 savaBatch()方法
第一种:普通for循环插入
@Test
public void testInsertBatch2() throws Exception {
long start = System.currentTimeMillis();
User user;
SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(false);
UserDao mapper = sqlSession.getMapper(UserDao.class);
for (int i = 0; i < 500; i++) {
user = new User();
user.setId("test" + i);
user.setName("name" + i);
user.setDelFlag("0");
mapper.insert(user);
}
sqlSession.commit();
long end = System.currentTimeMillis();
System.out.println("---------------" + (start - end) + "---------------");
}
<insert id="insert">
INSERT INTO t_user (id, name, del_flag)
VALUES(#{id}, #{name}, #{delFlag})
</insert>
第二种:mybatis BATCH模式插入
@Test
public void testInsertBatch2() throws Exception {
long start = System.currentTimeMillis();
User user;
SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);//跟上述sql区别
UserDao mapper = sqlSession.getMapper(UserDao.class);
for (int i = 0; i < 500; i++) {
user = new User();
user.setId("test" + i);
user.setName("name" + i);
user.setDelFlag("0");
# 因为继承了ServiceImpl ,所以可以调用 savaBatch()方法
mapper.insert(user);
}
sqlSession.commit();
long end = System.currentTimeMillis();
System.out.println("---------------" + (start - end) + "---------------");
}
<insert id="insert">
INSERT INTO t_user (id, name, del_flag)
VALUES(#{id}, #{name}, #{delFlag})
</insert>
第三种:foreach方式插入
@Test
public void testInsertBatch() throws Exception {
long start = System.currentTimeMillis();
List<User> list = new ArrayList<>();
User user;
for (int i = 0; i < 10000; i++) {
user = new User();
user.setId("test" + i);
user.setName("name" + i);
user.setDelFlag("0");
list.add(user);
}
# 因为继承了ServiceImpl ,所以可以调用 savaBatch()方法
userService.insertBatch(list);
long end = System.currentTimeMillis();
System.out.println("---------------" + (start - end) + "---------------");
}
<insert id="insertBatch">
INSERT INTO t_user
(id, name, del_flag)
VALUES
<foreach collection ="list" item="user" separator =",">
(#{user.id}, #{user.name}, #{user.delFlag})
</foreach >
</insert>
主键策略
(1)ID_WORKER
MyBatis-Plus默认的主键策略是:ID_WORKER 全局唯一ID
参考资料:分布式系统唯一ID生成方案汇总:https://www.cnblogs.com/haoxinyue/p/5208136.html
(2)自增策略
- 要想主键自增需要配置如下主键策略
- 需要在创建数据表的时候设置主键自增
- 实体字段中配置 @TableId(type = IdType.AUTO)
@TableId(type = IdType.AUTO)
private Long id;
要想影响所有实体的配置,可以设置全局主键配置
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto
其它主键策略:分析 IdType 源码可知
@Getter
public enum IdType {
/**
* 数据库ID自增
*/
AUTO(0),
/**
* 该类型为未设置主键类型
*/
NONE(1),
/**
* 用户输入ID
* 该类型可以通过自己注册自动填充插件进行填充
*/
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 全局唯一ID (idWorker)
*/
ID_WORKER(3),
/**
* 全局唯一ID (UUID)
*/
UUID(4),
/**
* 字符串全局唯一ID (idWorker 的字符串表示)
*/
ID_WORKER_STR(5);
private int key;
IdType(int key) {
this.key = key;
}
}