赞
踩
spring: # 数据源相关配置 datasource: username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver #时区必须配置否则报错,注意数据库名切换为自己的数据库名称 url: jdbc:mysql://127.0.0.1/itheima?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC #mybatis 相关配置 mybatis: # 指定接口映射文件的位置 mapper-locations: classpath:mapper/*.xml # 为POJO类指定别名 指定后使用时不再需要指定包名 type-aliases-package: com.itheima.integration.pojo # 开启debug日志 logging: level: com.itheima.springbootinit4: debug
@SpringBootApplication
@MapperScan("com.winter.dao")
public class SpringbootMybatisDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMybatisDemoApplication.class, args);
}
}
插入数据后获取自增主键的方案有两种,分别是使用<selectKey>
和useGeneratedKeys
属性
扩展 如果id为字符串类型,主键由uuid生成
#{} 【推荐】: 占位符, 相当于PreparedStatement对象, 会自动转换类型
pojo对象 #{对象中的属性名} -- 获取pojo中的属性
基本数据类型 #{参数名} -- 获取基本类型数据,参数名通过@Param("xxxx")指定
${} : 拼接符, 相当于字符串直接拼接, 不会自动转换类型,需要手动拼接类型
pojo对象 ${对象中的属性名} -- 获取pojo中的属性
基本数据类型 ${参数名} -- 获取基本类型数据,参数名通过@Param("xxxx")指定
User selectById( @Param("id") Integer id);
<!-- 属性 id 对应方法名,唯一 parameterType 参数的类型,可以省略 resultType 返回值类型 --> <select id="selectById" parameterType="java.lang.Integer" resultType="com.itheima.entity.User"> select * from t_user where id = #{id} </select> <!-- 获取mapper传入参数 1.简单类型:四类八种, String 获取:使用`#{}`直接获取参数,名称可以任意写(有注解时与注解保一致) 2.实体对象参数(POJO类) 获取:使用`#{}`直接获取对象的属性(有注解时,注解内容 点 属性) -->
<!-- 定义映射 id:映射的名字 type:实体类 --> <resultMap id="userResultMap" type="User"> <!-- 定义字段映射,id和result标签分别表示主键字段映射和非主键字段映射 property 实体类中的属性名 column SQL返回结果的列名 如果property和cloumn的值相同,可以省略 --> <id property="id" column="id"/> <result property="userName" column="user_name"/> <result property="birthday" column="birthday"/> <result property="sex" column="sex"/> <result property="homeAddress" column="home_address"/> </resultMap>
<!-- where: 1. where标签就相当于SQL语句中where关键字 2. 去掉多余的and、or关键字 if: 判断条件是否为真,如果为真则将if中字符串拼接到SQL语句中 --> <select id="selectByUserNameAndSex" resultMap="userResultMap"> select * from t_user <where> <if test="userName!=null and userName!=''"> user_name=#{userName} </if> <if test="sex!=null and sex!=''"> and sex=#{sex} </if> </where> </select>
<!-- set 1.一般与if标签配合使用 2.set用在update语句中,相当于set关键字 3.会自动去掉能多余的逗号 --> <update id="updateByIdSelective"> update t_user <set> <if test="userName!=null"> user_name = #{userName}, </if> <if test="birthday!=null"> birthday = #{birthday}, </if> <if test="sex!=null"> sex = #{sex}, </if> <if test="homeAddress!=null"> home_address = #{homeAddress}, </if> </set> where id=#{id} </update>
<insert id="insertRecords"> insert into t_user values <foreach collection="users" item="user" separator=","> (#{user.id}, #{user.userName}, #{user.birthday}, #{user.sex}, #{user.homeAddress}) </foreach> </insert> <delete id="deleteByIdS"> delete from t_user where id in <!-- open 遍历开始前添加的符号 close 遍历完成后添加的符号 --> <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach> </delete>
<!--定义可重用的代码块--> <sql id="conditionSql"> <if test="condition!=null and condition!=''"> where user_name like concat('%',#{condition},'%') or home_address like concat('%',#{condition},'%') </if> </sql> <!--根据条件查询--> <select id="selectByConditon" resultMap="userResultMap"> select * from t_user <!--引用代码块--> <include refid="conditionSql"/> </select> <!--根据条件统计--> <select id="countByConditon" resultType="int"> select count(1) from t_user <!--引用代码块--> <include refid="conditionSql"/> </select>
当SQL查询的结果集复杂,不能(或不方便)使用一个类结构来接收这些数据,我们就称这种映射是复杂映射。复杂映射一般分为两种:一对一、一对多。
一对一映射通过<assosication>
标签实现;一对多映射通过<collection>
标签实现。
<!-- 一对多映射 1. collection标签,用于表示数据查询中的1对多映射 2. 此时,resultMap和collection都需要指定所有字段的映射,不能省略(同association) 3. SQL查询的结果集中不能有重复的字段,如果有重复字段,则映射过程中只有第一个字段可以取到正确的值,所以需要给名称重复的字段使用别名。(同association) --> <resultMap id="userAndOrderResultMap" type="User"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="birthday" column="birthday"/> <result property="sex" column="sex"/> <result property="address" column="address"/> <!-- collection 映射成一个集合 porperty 类属的属性名 ofType 集合内元素的类型 --> <collection property="orders" ofType="Order" > <id property="id" column="o_id"/> <result property="userId" column="o_user_id"/> <result property="goods" column="o_goods"/> <result property="createTime" column="o_create_time"/> <result property="note" column="o_note"/> </collection> </resultMap> <select id="selectUserAndOrderById" resultMap="userAndOrderResultMap"> SELECT tu.*, tor.id o_id, tor.user_id o_user_id, tor.goods o_goods, tor.create_time o_create_time, tor.note o_note FROM t_user tu join t_order tor on tu.id=tor.user_id where tu.id=#{id} </select>
public interface UserMapper{
/**
* 查询所有用户基本信息、拓展细信、订单
*
* @return
*/
List<User> selectAllUserAndInfoAndOrder();
}
<!--用户详细信映射--> <resultMap id="userDetailResultMap" type="User"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="birthday" column="birthday"/> <result property="sex" column="sex"/> <result property="address" column="address"/> <!-- association和collection都可以通过column属性和select属性配合完成级联查询操作 select 子查询,一个select标签的id column 指定参数传递 --> <association property="userInfo" column="id" select="selectUserInfoByUserId"/> <collection property="orders" column="id" select="selectOrderByUserId"/> </resultMap> <!--用户拓展信息映射--> <resultMap id="userInfoResultMap" type="UserInfo"> <result property="userId" column="user_id"/> </resultMap> <!--订单信息映射--> <resultMap id="orderResultMap" type="Order"> <result property="userId" column="user_id"/> <result property="createTime" column="create_time"/> </resultMap> <!--查询用户信息--> <select id="selectAllUserAndInfoAndOrder" resultMap="userDetailResultMap"> select * from t_user </select> <!--查询用户拓展信--> <select id="selectUserInfoByUserId" resultMap="userInfoResultMap"> select * from t_user_info where user_id=#{userId} </select> <!--查询订单信--> <select id="selectOrderByUserId" resultMap="orderResultMap"> select * from t_order where user_id=#{userId} </select>
当自动映射查询结果时,MyBatis 会获取结果(sql查询结果集)中返回的列名并在 Java 类中查找相同名字的属性(忽略大小写)。 这意味着如果发现了 ID 列和 id 属性,MyBatis 会将列 ID 的值赋给 id 属性。
通常数据库列使用大写字母组成的单词命名,单词间用下划线分隔;而 Java 属性一般遵循驼峰命名法约定。
@Select(“查询语句”)查询;
@Update(“更新语句”)更新;
@Delete(“删除语句”)删除;
@Insert(“插入语句”)插入;
@SelectKey()
public interface UserMapper { @Select(value = "select * from t_user where username like concat('%',#{username},'%')") List<User> selectByLike(String username); /** * 分页查询 * @param startIndex * @param pageSize * @return */ @Select(value = "select * from t_user limit #{param1}, #{param2}") List<User> selectByPage1(Integer startIndex, Integer pageSize); /** * 分页查询 * @param startIndex * @param pageSize * @return */ @Select(value = "select * from t_user limit #{startIndex}, #{pageSize}") List<User> selectByPage2(@Param("startIndex") Integer startIndex, @Param("pageSize") Integer pageSize); /** * 查询所有 * @return */ @Select(value = "select * from t_user") List<User> selectAll(); /** * 通过id查询用户基础信息 */ @Select(value="select * from t_user where id = #{id}") User selectById(@Param("id") Integer id); /** * 更新用户信息基础信息 * @param user * @return */ @Update(value=" update t_user set username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address} where id=#{id}") int update(User user); /** * 更新用户信息基础信息 * @param id * @return */ @Delete(value=" delete from t_user where id=#{id}") int deleteById(@Param("id") Integer id); /** * 插入 * @param user * @return */ @Insert("insert into t_user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})") @SelectKey(resultType = Integer.class,keyProperty ="id",before = false,statement = "select LAST_INSERT_ID()") int insert(User user); }
@Results:
@Result
@Results:
含义:封装映射关系的父注解。
属性
value: 定义了Result 数组
@Result
含义:封装映射关系的子注解。
属性
id: 是否是主键
column:查询出的表中字段名称
property 属性:实体对象中的属性名称
javaType属性:被包含对象的数据类型
@One
@Results(value = {
@Result(id = true, column = "id", property = "id"),
@Result(column = "user_name", property = "userName"),
@Result(column = "sex", property = "sex"),
@Result(column = "birthday", property = "birthday"),
@Result(column = "home_address", property = "homeAddress"),
@Result(
property = "userInfo",
column = "id",
one = @One(select = "com.itheima.dao.UserInfoMapper.selectUserInfoByUserId"))
})
@Select(value="select * from t_user where id = #{id}")
User selectById(@Param("id") Integer id);
public interface UserInfoMapper {
@Select("select * from t_user_info where user_id = #{user_id}")
UserInfo selectUserInfoByUserId(Integer userId);
}
@Results : 映射结果集
@Result: 映射某一列
@One: 一对一映射
@Many: 一对多映射
@Results(value = { @Result(id = true, column = "id", property = "id"), @Result(column = "user_name", property = "userName"), @Result(column = "sex", property = "sex"), @Result(column = "birthday", property = "birthday"), @Result(column = "home_address", property = "homeAddress"), @Result( property = "userInfo", column = "id", one = @One(select = "com.itheima.dao.UserInfoMapper.selectUserInfoByUserId")), @Result( property = "orders", column = "id", many = @Many(select = "com.itheima.dao.OrderMapper.selectOrderListByUserId")) }) @Select(value="select * from t_user where id = #{id}") User selectById(@Param("id") Integer id);
public interface UserInfoMapper {
@Select("select * from t_user_info where user_id = #{user_id}")
UserInfo selectUserInfoByUserId(Integer userId);
}
@Results : 映射结果集
@Result: 映射某一列
@Many: 一对多映射
MyBatis的缓存
@Transactional注解和Mybatis缓存问题
mybatis springboot 开启缓存
mybatis缓存分为 一级缓存和二级缓存
注:
缓存只针对于DQL语句,也就是说缓存机制只对应select语句。
在springboot中,使用了数据库连接池,默认每次查询后自动提交(commite),导致两次查询 不是一个sqlSession,根据一级缓存原理,它不会生效
缓存优先级: 二级>一级>数据库
①⼀级缓存默认是开启的,不需要做任何配置。
②原理:只要使⽤同⼀个SqlSession对象执⾏同⼀条SQL语句,就会⾛缓存。
使⽤⼆级缓存需要具备以下⼏个条件:
① 全局性地开启或关闭所有映射器配置⽂件中已配置的任何缓存。默认就是true,⽆需设置(默认>二级缓存就是开启的)!
②在需要使⽤⼆级缓存的SqlMapper.xml⽂件中添加一个标签:
③使⽤⼆级缓存的实体类对象必须是可序列化的,也就是必须实现java.io.Serializable接⼝
④SqlSession对象关闭或提交之后,⼀级缓存中的数据才会被写⼊到⼆级缓存当中;此时⼆级缓存才可⽤。
集成EhCache是为了代替MyBatis⾃带的⼆级缓存,⼀级缓存是⽆法替代的!
国内研发,在 MyBatis 的基础上只做增强不做改变
官网
<!--SpringBoot-->
<dependency>
<groupId>com.baomidou</groupId>
<!--下面坐标根据自己使用的SpringBoot版本二选一-->
<!--SpringBoot2使用此版本-->
<artifactId>mybatis-plus-boot-starter</artifactId>
<!--3.5.4开始,支持SpringBoot3使用此版本-->
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>最新版本</version>
</dependency>
mybatis-plus: mapper-locations: classpath:net/cnki/editor/expense/dao/impl/*.xml #类型:String[] #默认值:["classpath*:/mapper/**/*.xml"] #MyBatis Mapper 所对应的 XML 文件位置,如果您在 Mapper 中有自定义方法(XML 中有自定义实现),需要进行该配置,告诉 Mapper 所对应的 XML 文件位置,Maven 多模块项目的扫描路径需以 classpath*: 开头 (即加载多个 jar 包下的 XML 文件) type-aliases-package: net.cnki.editor.expense.dos #类型:String #默认值:null #MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML 文件中可以直接使用类名,而不用使用全限定的类名(即 XML 中调用的时候不用包含包名) configuration.map-underscore-to-camel-case: true #类型:boolean #默认值:true #是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射。 global-config.db-config.id-type: assign_id # 类型:com.baomidou.mybatisplus.annotation.IdType #默认值:ASSIGN_ID #全局默认主键类型
在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:
每天一个注解之@MapperScan
@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
描述:表名注解,标识实体类对应的表
使用位置:实体类
描述:主键注解
使用位置:实体类主键字段
描述:字段注解(非主键)
@SpringBootApplication
@MapperScan("com.winter.dao")
public class SpringbootMybatisDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMybatisDemoApplication.class, args);
}
}
@TableName("tb_user") @Data public class User { //设置id生成策略:AUTO 数据库自增 @TableId(type = IdType.AUTO) private Long id; //@TableField("user_name") private String userName; private String password; private String name; private Integer age; private String email; //不希望该值存入数据库 // @TableField(exist = false) // private String info; }
/**
* 使用mp定义Mapper,需要让Mapper接口继承 BaseMapper接口。
*/
public interface UserMapper extends BaseMapper<User> {
}
public interface _UserService extends IService<User> {
}
@Service
public class _UserServiceImpl extends ServiceImpl<UserMapper, User> implements _UserService {}
@Configuration public class PageConfig { /** * 3.4.0之前的版本用这个 * @return */ /* @Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); }*/ /** * 3.4.0之后提供的拦截器的配置方式 * @return */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return mybatisPlusInterceptor; } }
/** * 分页查询: * 1. 当前页码:currentPage * 2. 每页显示条数:size * * 注意:使用mp的分页要设置一个拦截器!!! */ @Test public void testSelectPage() { int current = 1;//当前页码 int size = 2;//每页显示条数 IPage<User> page = new Page(current,size); userMapper.selectPage(page,null); List<User> records = page.getRecords();//当前页的数据 long pages = page.getPages();//总页数 2 long total = page.getTotal();//总记录数 4 System.out.println(records); System.out.println(pages); System.out.println(total); }
基础比较查询 Wrapper()包装器://条件构建器 1.QueryWrapper LambdaQueryWrapper 2.UpdateWrapper LambdaUpdateWrapper 方法: eq( ) : 等于 = ne( ) : 不等于 <> gt( ) : 大于 > ge( ) : 大于等于 >= lt( ) : 小于 < le( ) : 小于等于 <= between ( ) : BETWEEN 值1 AND 值2 notBetween ( ) : NOT BETWEEN 值1 AND 值2 in( ) : in notIn( ) :not in 逻辑查询 or( ) :让紧接着下一个方法用or连接 模糊查询 like 查询关键字前后都加% notLike likeLeft likeRight 排序查询 orderBy orderByAsc通过某个条件正排 orderByDesc反排 select:指定需要查询的字段
@Test
public void testWrapper2(){
//1.创建查询条件构建器
QueryWrapper<User> wrapper = new QueryWrapper<>();
//2.设置条件
wrapper.eq("user_name","lisi")
.or()
.lt("age",23)
.in("name","李四","王五");
/*
select * from tb_user where user_name = ? or age < ? and name in (?,?)
*/
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}
LambdaQueryWrapper:消除代码中的硬编码
@Test
public void testWrapper7(){
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUserName,"zhangsan");
userMapper.selectOne(wrapper);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。