初识Mybatis

MyBatis

初识Mybatis

1.导入mybatis相关依赖
 

xml

代码解读

复制代码

<dependencies> <!--mybatis的核心依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> <!--mysql驱动依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.42</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> </dependencies>

2.创建pojo,将pojo和数据表进行关联映射,定义接口

创建Bean :User类

 

java

代码解读

复制代码

@Data @NoArgsConstructor @AllArgsConstructor public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; }

定义数据持久层接口类:UserDao

 

java

代码解读

复制代码

public interface UserDao { List<User> queryAll(); }

3.创建mybatis核心配置文件sqlMapConfig.xml
 

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"> <configuration> <!--配置mybatis的环境--> <environments default="mysql"> <!--配置mysql的环境--> <environment id="mysql"> <!--配置事务的类型,我们使用JDBC的事务--> <transactionManager type="JDBC"></transactionManager> <!-- 配置连接数据库的信息,用的是数据源(连接池) type: POOLED 使用默认的数据库连接 UNPOOLED --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"/> <property name="username" value="root"/> <property name="password" value="rootroot"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/duoduo/dao/UserDao.xml"></mapper> </mappers> </configuration>

4.创建接口的映射文件

接口所在的目录和接口文件的目录保持一致。

 

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.duoduo.dao.UserDao"> <!-- 配置查询所有的操作 id:方法名称 和接口的方法名称对应 parameterType: 参数值类型(全限定名) resultType: 返回值类型(全限定名) --> <select id="queryAll" resultType="com.duoduo.pojo.User"> select * from user </selct> </mapper>

5.编写测试代码
 

java

代码解读

复制代码

@Test public void testQueryAll() throws Exception { //加载mybatis的核心配置文件 InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml"); //创建sqlSessionFactoryBuilder SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //创建SqlSessionFactory对象(构建者设计模式,屏蔽了SqlSessionFactory创建的细节) SqlSessionFactory factory = builder.build(inputStream); //创建SqlSession对象(工厂模式) SqlSession session = factory.openSession(); //通过SqlSession生成接口的代理对象(生成动态代理的思想) UserDao userDao = session.getMapper(UserDao.class); List<User> users = userDao.queryAll(); users.forEach(user -> System.out.println(user)); //关闭资源 session.close(); inputStream.close(); }

测试结果:

单表操作(UserDao.xml)

单表的查询、更新
 

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.duoduo.dao.UserDao"> <!-- 查询所有的用户信息 --> <select id="queryAllUser" resultType="com.duoduo.pojo.User"> select * from user </select> <!-- 根据id查询用户信息 id:定义接口的名称 resultType: 方法的返回值类型 parameterType: 形参的数据类型 --> <select id="queryUserById" resultType="com.duoduo.pojo.User" parameterType="int"> select * from user where id = #{id} </select> <insert id="addUser" parameterType="com.duoduo.pojo.User" useGeneratedKeys="true" keyProperty="id" keyColumn="id"> <!-- selectKey 获取自增长主键的标签 keyColum:数据表中主键的字段名称 keyProperty:实体类映射主键字段的属性 resultType:主键的数据类型 select 240308 是mysql的系统函数,专门用来获取新增之后主键的值 --> <!--<selectKey keyColumn="id" keyProperty="id" resultType="Integer"> select 240308 </selectKey>--> insert into user(username, birthday, sex, address) VALUES (#{username},#{birthday},#{sex},#{address}) </insert> <update id="updateUser" parameterType="com.duoduo.pojo.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id = #{id} </update> <delete id="deleteUserById" parameterType="int"> delete from user where id = #{id} </delete> </mapper>

模糊查询

UserDao.xml 配置文件的编写

 

xml

代码解读

复制代码

<select id="queryDimUserByUsername" parameterType="string" resultType="com.duoduo.pojo.User"> select * from user where username like #{username} </select> <select id="queryDimUserByUsername2" parameterType="string" resultType="com.duoduo.pojo.User"> select * from user where username like '%${value}%' </select>

测试类的编写,不同的写法测试类也不同

 

java

代码解读

复制代码

@Test public void testDimQuery(){ List<User> users = userDao.queryDimUserByUsername("%王%"); users.forEach(user -> System.out.println(user)); session.commit(); } @Test public void testDimQuery2(){ List<User> users = userDao.queryDimUserByUsername2("王"); users.forEach(user -> System.out.println(user)); session.commit(); }

#{} 和 ${} 的区别:

#{}表示一个占位符号 通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换, #{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类 型值,#{}括号中可以是 value 或其它名称。

表示拼接sql串通过表示拼接sql串通过{}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, 可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,∗∗可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,∗∗{}括号中只能是value。**(使用的是statement)

在接口中传入多个参数的问题

数据控制层Dao

 

java

代码解读

复制代码

List<User> queryUserByMap(Map<String,Object> map);

UserDao.xml 配置文件的编写

 

xml

代码解读

复制代码

<select id="queryUserByMap" parameterType="map" resultType="com.duoduo.pojo.User"> select * from user where sex = #{sex} and address = #{address} </select>

测试类:

 

java

代码解读

复制代码

public void testQueryMap(){ Map<String,Object> map = new HashMap<>(); map.put("sex","男"); map.put("address","广东深圳"); List<User> users = userDao.queryUserByMap(map); users.forEach(user -> System.out.println(user)); }

pojo封装同一类型参数的对象
 

java

代码解读

复制代码

@Getter @Setter public class QueryIds { private List<Integer> ids; }

数据控制层Dao

 

java

代码解读

复制代码

List<User> queryUserByIds(QueryIds queryIds);

UserDao.xml 配置文件的编写

 

xml

代码解读

复制代码

<select id="queryUserByIds" parameterType="com.duoduo.pojo.QueryIds" resultType="com.duoduo.pojo.User"> select * from user where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach> </select>

测试类:

 

java

代码解读

复制代码

public void testQueryIds(){ List<Integer> ids = new ArrayList<>(); Collections.addAll(ids,41,43,45,52); QueryIds queryIds = new QueryIds(); queryIds.setIds(ids); List<User> users = userDao.queryUserByIds(queryIds); users.forEach(user -> System.out.println(user)); }

用集合实现

数据控制层Dao

 

java

代码解读

复制代码

List<User> queryUserByList(List<Integer> ids);

UserDao.xml 配置文件的编写

 

xml

代码解读

复制代码

<select id="queryUserByList" parameterType="list" resultType="user"> select * from user where id in <foreach collection="collection" item="id" separator="," open="(" close=")"> #{id} </foreach> </select>

测试类:

 

java

代码解读

复制代码

public void testQueryByList(){ List<Integer> ids = new ArrayList<>(); Collections.addAll(ids,41,43,45,52); List<User> users = userDao.queryUserByList(ids); users.forEach(user -> System.out.println(user)); }

用集合实现2

数据控制层Dao

在形参前面添加一个@Param() 注解 ,里面的内容是后续UserDao.xml里面需要传入的collection值

 

java

代码解读

复制代码

List<User> queryUserByList(@Param("ids") List<Integer> ids);

UserDao.xml 配置文件的编写

foreach标签里面 collection的值引用的是Dao层@Param注解里面的值

 

xml

代码解读

复制代码

<select id="queryUserByList" parameterType="list" resultType="user"> select * from user where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach> </select>

测试类:

 

java

代码解读

复制代码

public void testQueryByList(){ List<Integer> ids = new ArrayList<>(); Collections.addAll(ids,41,43,45,52); List<User> users = userDao.queryUserByList(ids); users.forEach(user -> System.out.println(user)); }

用数组实现

数据控制层Dao

 

java

代码解读

复制代码

List<User> queryUserByArray(Integer[] arr);

UserDao.xml 配置文件的编写

 

xml

代码解读

复制代码

<select id="queryUserByArray" parameterType="int[]" resultType="user"> select * from user where id in <foreach collection="array" item="id" separator="," open="(" close=")"> #{id} </foreach> </select>

测试类:

 

java

代码解读

复制代码

public void testQueryByArray(){ Integer[] arr = {41,43,45,52}; List<User> users = userDao.queryUserByArray(arr); users.forEach(user -> System.out.println(user)); }

用数组实现2

数据控制层Dao

在形参前面添加一个@Param() 注解 ,里面的内容是后续UserDao.xml里面需要传入的collection值

 

java

代码解读

复制代码

List<User> queryUserByArray(@Param("ids") Integer[] arr);

UserDao.xml 配置文件的编写

foreach标签里面 collection的值引用的是Dao层@Param注解里面的值

 

xml

代码解读

复制代码

<select id="queryUserByArray" parameterType="int[]" resultType="user"> select * from user where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach> </select>

测试类:

 

java

代码解读

复制代码

public void testQueryByArray(){ Integer[] arr = {41,43,45,52}; List<User> users = userDao.queryUserByArray(arr); users.forEach(user -> System.out.println(user)); }

SqlMapConfig.xml的一些细节
SqlMapConfig.xml 中配置的内容和顺序

-properties(属性)

​ --property

-settings(全局配置参数)

​ --setting

-typeAliases(类型别名)

​ --typeAliase

​ --package

-typeHandlers(类型处理器)

-objectFactory(对象工厂)

-plugins(插件)

-environments(环境集合属性对象)

​ --environment(环境子属性对象)

​ ---transactionManager(事务管理)

​ ---dataSource(数据源)

-mappers(映射器)

​ --mapper

​ --package

properties标签

​ 读取properties文件内的信息

 

xml

代码解读

复制代码

<properties resource="db.properties"></properties> <environments default="mybatis"> <environment id="mybatis"> <transactionManager type="JDBC"></transactionManager> <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>

typeAliases标签

自定义别名方式。

配置sqlMapConfig.xml

 

xml

代码解读

复制代码

<typeAliases> <typeAlias type="com.duoduo.pojo.User" alias="user"></typeAlias> </typeAliases>

修改映射文件UserDao.xml,使用别名替换

 

xml

代码解读

复制代码

<select id="queryAllUser" resultType="user"> select * from user </select>

另外一种写法

 

xml

代码解读

复制代码

<typeAliases> <!--<typeAlias type="com.xq.pojo.User" alias="user"></typeAlias>--> <!-- 在当前包下的所有类的别名均设置为类名的小写 --> <package name="com.duoduo.pojo"/> </typeAliases>

Mappers标签

Mappers标签里面定义mapper标签。作用是用来在核心配置文件里面引入映射文件。

第一种:

 

xml

代码解读

复制代码

<mappers> <mapper resource="com/duoduo/dao/UserDao.xml"></mapper> </mappers>

第二种:

使用 mapper 接口类路径。如果我们使用注解开发的时候,就需要使用这个路径

 

xml

代码解读

复制代码

<mappers> <!--路径层级之间用 / 拼接--> <mapper class="com.xq.dao.UserDao"></mapper> </mappers>

第三种:

 

xml

代码解读

复制代码

<mappers> <!--<mapper resource="com/duoduo/dao/UserDao.xml"></mapper>--> <!--路径层级之间用 . 拼接--> <package name="com.duoduo.dao"/> </mappers>

动态SQL

动态查询(if标签 、where标签)

数据控制层Dao

 

java

代码解读

复制代码

public interface UserDao { List<User> queryUserByLive(User user); List<User> queryUserByLive2(User user); }

UserDao.xml 配置文件的编写

 

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.duoduo.dao.UserDao"> <select id="queryUserByLive" resultType="user" parameterType="user"> select * from user where 1 = 1 <if test="id != null and id != ''"> and id = #{id} </if> <if test="username != null and username != ''"> and username = #{username} </if> <if test="birthday != null and birthday != ''"> and birthday = #{birthday} </if> <if test="sex != null and sex != ''"> and sex = #{sex} </if> <if test="address != null and address != ''"> and address = #{address} </if> </select> <select id="queryUserByLive2" resultType="user" parameterType="user"> select * from user <!-- where 标签 替换了where 1 = 1 where标签本身解析成sql语句中的where关键字 并且在底层解析sql的时候,满足条件的第一个if标签,会将if里面的and给去掉 --> <where> <if test="id != null and id != ''"> and id = #{id} </if> <if test="username != null and username != ''"> and username = #{username} </if> <if test="birthday != null and birthday != ''"> and birthday = #{birthday} </if> <if test="sex != null and sex != ''"> and sex = #{sex} </if> <if test="address != null and address != ''"> and address = #{address} </if> </where> </select> </mapper>

测试类:

 

java

代码解读

复制代码

public void testLiveQuery(){ User user = new User(); user.setUsername("tom"); user.setSex("男"); user.setAddress("广东深圳"); List<User> users = userDao.queryUserByLive(user); users.forEach(u -> System.out.println(u)); } public void testLiveQuery2(){ User user = new User(); user.setUsername("tom"); user.setSex("男"); user.setAddress("广东深圳"); List<User> users = userDao.queryUserByLive2(user); users.forEach(u -> System.out.println(u)); }

总结:
 

txt

代码解读

复制代码

where 标签 替换了where 1 = 1 where标签本身解析成sql语句中的where关键字 并且在底层解析sql的时候,满足条件的第一个if标签,会将if里面的and给去掉

动态查询(where choose when otherwise 标签)

数据控制层Dao

 

java

代码解读

复制代码

List<User> queryUserByLive3(User user);

UserDao.xml 配置文件的编写

 

xml

代码解读

复制代码

<select id="queryUserByLive3" resultType="user" parameterType="user"> select * from user <where> <choose> <when test="username != null and username != '' "> username = #{username} </when> <when test="birthday != null and birthday != '' "> birthday = #{birthday} </when> <when test="sex != null and sex != '' "> sex = #{sex} </when> <when test="address != null and address != '' "> address = #{address} </when> <otherwise> id = #{id} </otherwise> </choose> </where> </select>

测试类:

 

java

代码解读

复制代码

public void testLiveQuery3(){ User user = new User(); user.setUsername("tom"); user.setSex("男"); user.setAddress("广东深圳"); List<User> users = userDao.queryUserByLive3(user); users.forEach(u -> System.out.println(u)); }

8.png

 

java

代码解读

复制代码

public void testLiveQuery3(){ User user = new User(); user.setId(52); List<User> users = userDao.queryUserByLive3(user); users.forEach(u -> System.out.println(u)); }

9.png

总结:

类似于Java语言中的

if(条件1){

​ ....

} else if(条件2){

​ ....

}else if(条件3){

​ ....

} else {

​ ....

}

 

txt

代码解读

复制代码

choose when 标签 :当条件满足当前标签,将不再向下执行 otherwise 标签: 当前面所有when标签的条件都不满足时,执行otherwise标签的内容

动态修改(set标签)

数据控制层Dao

 

java

代码解读

复制代码

void updateUserByLive(User user);

UserDao.xml 配置文件的编写

 

xml

代码解读

复制代码

<update id="updateUserByLive" parameterType="user"> update user <!-- set 标签 set 标签自动解析成了sql语句的set关键字 并且底层在解析set的时候,将最后一个if中的内容的逗号(,)去除,以保证sql语句执行的正确性。 --> <set> <if test="username != null and username != ''"> username = #{username}, </if> <if test="birthday != null and birthday != ''"> birthday = #{birthday}, </if> <if test="sex != null and sex != ''"> sex = #{sex}, </if> <if test="address != null and address != ''"> address = #{address}, </if> </set> where id = #{id} </update>

测试类:

 

java

代码解读

复制代码

public void testLiveUpdate(){ User user = new User(); user.setUsername("tom"); user.setSex("男"); user.setAddress("广东深圳"); userDao.updateUserByLive(user); }

动态新增(sql标签 trim标签 include标签)

数据控制层Dao

 

java

代码解读

复制代码

void insertUserByLive(User user);

UserDao.xml 配置文件的编写

 

xml

代码解读

复制代码

<sql id="insertUserKey"> <trim suffixOverrides=","> <if test="username != null and username != '' "> username, </if> <if test="birthday != null and birthday != '' "> birthday, </if> <if test="sex != null and sex != '' "> sex, </if> <if test="address != null and address != '' "> address, </if> </trim> </sql> <sql id="insertUserValue"> <trim suffixOverrides=","> <if test="username != null and username != '' "> #{username}, </if> <if test="birthday != null and birthday != '' "> #{birthday}, </if> <if test="sex != null and sex != '' "> #{sex}, </if> <if test="address != null and address != '' "> #{address}, </if> </trim> </sql> <insert id="insertUserByLive" parameterType="user"> insert into user(<include refid="insertUserKey"></include>) values (<include refid="insertUserValue"></include>) </insert>

测试结果:

7.png

※批处理

新增

数据持久层Dao

 

java

代码解读

复制代码

void insertUsers(User user);

UserDao.xml 配置文件的编写

 

xml

代码解读

复制代码

<insert id="insertUsers" parameterType="user"> insert into user(username, birthday, sex, address) VALUES (#{username},#{birthday},#{sex},#{address}) </insert>

测试类:

 

java

代码解读

复制代码

public void testInsertUsers(){ List<User> list = new ArrayList<>(); User user1 = new User(); user1.setUsername("测试数据1"); user1.setBirthday(new Date()); user1.setSex("N"); user1.setAddress("测试数据1"); User user2 = new User(); user2.setUsername("测试数据2"); user2.setBirthday(new Date()); user2.setSex("N"); user2.setAddress("测试数据2"); User user3 = new User(); user3.setUsername("测试数据3"); user3.setBirthday(new Date()); user3.setSex("N"); user3.setAddress("测试数据3"); Collections.addAll(list,user1,user2,user3); list.forEach(user -> userDao.insertUsers(user)); }

10.png

当未开启mybatis批处理的情况下,sql语句会预编译三次

开启批处理

注意!!!:开启批处理以后,要手动进行事务的提交

​ 开启方式1:

​ 在mybatis核心配置文件中添加标签 并设置参数 name="defaultExecutorType" value="BATCH"

 

xml

代码解读

复制代码

<!--开启批处理--> <settings> <setting name="defaultExecutorType" value="BATCH"/> </settings>

​ 开启方式2:

​ 在创建SqlSession对象的时候,指定开启批处理

 

java

代码解读

复制代码

SqlSession session = factory.openSession(ExecutorType.BATCH,false);

11.png

多表查询

一对一查询

一个账户对应着一个用户,在Account类中维护一个属性User user

 

java

代码解读

复制代码

@Getter @Setter @ToString public class Account { private Integer aid; private Integer uid; private Double money; //维护一个实体User属性 private User user; }

数据持久层Dao

 

csharp

代码解读

复制代码

List<Account> queryAccountAndUser();

UserDao.xml 配置文件的编写

一对一的实体维护:association 标签 内部属性是 javaType

 

xml

代码解读

复制代码

<resultMap id="accountUserMap" type="account"> <id column="aid" property="aid"></id> <result column="uid" property="uid"></result> <result column="money" property="money"></result> <association property="user" javaType="user"> <id column="id" property="id"></id> <result column="username" property="username"></result> <result column="birthday" property="birthday"/> <result column="sex" property="sex"></result> <result column="address" property="address"></result> </association> </resultMap> <select id="queryAccountAndUser" resultMap="accountUserMap"> select account.AID, account.UID, account.MONEY,user.id,user.username,user.address from account,user where UID = user.id; </select>

测试类:

 

java

代码解读

复制代码

public void testQueryAccountUser(){ List<Account> accounts = accountDao.queryAccountAndUser(); accounts.forEach(account -> System.out.println(account)); }

一对多查询

一个用户对应多个账户,在User中添加一个List 对accounts进行维护

 

java

代码解读

复制代码

@Data public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; private List<Account> accounts; }

数据持久层Dao

 

java

代码解读

复制代码

List<User> queryUserAndAccount();

UserDao.xml 配置文件的编写

一对多的实体维护:collection 标签,内部属性是ofType(写集合的范型)

 

xml

代码解读

复制代码

<resultMap id="userAccountMap" type="com.duoduo.pojo.User"> <id column="id" property="id"></id> <result column="username" property="username"></result> <result column="birthday" property="birthday"></result> <result column="sex" property="sex"></result> <result column="address" property="address"></result> <collection property="accounts" ofType="account"> <id column="aid" property="aid"/> <result column="uid" property="uid"/> <result column="money" property="money"/> </collection> </resultMap> <select id="queryUserAndAccount" resultMap="userAccountMap"> select user.id, username, birthday, sex, address,account.MONEY from user,account where account.UID = user.id; </select>

测试类:

 

java

代码解读

复制代码

public void testQueryAccountUser(){ List<User> users = userDao.queryUserAndAccount(); users.forEach(user -> System.out.println(user)); }

多对多查询

 

java

代码解读

复制代码

@Data public class Role { private Integer roleId; private String roleName; private String roleDesc; private List<User> users; }

数据持久层Dao

 

java

代码解读

复制代码

List<Role> queryRoleAndUser();

UserDao.xml 配置文件的编写

和一对多好像是一样的

 

xml

代码解读

复制代码

<resultMap id="roleMap" type="role"> <id column="rid" property="roleId"></id> <result column="role_name" property="roleName"></result> <result column="role_desc" property="roleDesc"></result> <collection property="users" ofType="user"> <id column="id" property="id"></id> <result column="username" property="username"></result> <result column="birthday" property="birthday"></result> <result column="sex" property="sex"></result> <result column="address" property="address"></result> </collection> </resultMap> <select id="queryRoleAndUser" resultMap="roleMap"> select role.*,user.username,user.address from role,user_role,user where role.RID = user_role.RID and user.id = user_role.UID </select>

测试类:

 

java

代码解读

复制代码

public void testQueryAccountUser(){ List<Role> roles = roleDao.queryRoleAndUser(); roles.forEach(role -> System.out.println(role)); }

Mybatis延时加载策略

Account

 

java

代码解读

复制代码

@Getter @Setter @ToString public class Account { private Integer aid; private Integer uid; private Double money; private User user; }

User

 

java

代码解读

复制代码

@Data public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; }

AccountDao

 

java

代码解读

复制代码

public interface AccountDao { List<Account> queryAllAccount(); }

UserDao

 

java

代码解读

复制代码

public interface UserDao { List<User> queryUserById(Integer id); }

AccountDao.xml

 

xml

代码解读

复制代码

<resultMap id="accountMap" type="account"> <id column="aid" property="aid"></id> <result column="uid" property="uid"></result> <result column="money" property="money"></result> <association property="user" column="uid" select="com.duoduo.dao.UserDao.queryUserById"></association> </resultMap> <select id="queryAllAccount" resultMap="accountMap"> select * from account </select>

UserDao.xml

 

xml

代码解读

复制代码

<select id="queryUserById" resultType="user" parameterType="int"> select * from user where id = #{id} </select>

测试类:

 

java

代码解读

复制代码

@Test public void testQueryAccountUser(){ List<Account> accounts = accountDao.queryAllAccount(); //accounts.forEach(account -> System.out.println(account)); }

12.png

执行了三条sql语句并没有延时加载的效果

延时加载配置

方式一:mybatis主要配置文件
 

xml

代码解读

复制代码

<settings> <setting name="lazyLoadingEnabled" value="true"/> <!-- mybatis3.4.1版本后可以不写,默认为false。 --> <setting name="aggressiveLazyLoading" value="false"/> </settings>

方式二:AccountDao.xml文件配置

在association标签内添加一个fetchType属性 值为lazy即可做到懒加载

 

xml

代码解读

复制代码

<resultMap id="accountMap" type="account"> <id column="aid" property="aid"></id> <result column="uid" property="uid"></result> <result column="money" property="money"></result> <association property="user" column="uid" select="com.duoduo.dao.UserDao.queryUserById" fetchType="lazy"></association> </resultMap> <select id="queryAllAccount" resultMap="accountMap"> select * from account </select>

测试类:

一定要把forEach语句注释掉

 

java

代码解读

复制代码

@Test public void testQueryAccountUser(){ List<Account> accounts = accountDao.queryAllAccount(); //accounts.forEach(account -> System.out.println(account)); }

13.png

Mybatis缓存

  • 什么是缓存

    • 缓存就是存在内存中的数据
  • 为什么使用缓存

    • 减少和数据库交互的次数,提高执行效率

      ​ 因为数据库中的数据文件本质上其实是存储在硬盘上的(加密)文件,所以从内存中查找是要比从硬盘中查询是要块的

  • 什么样的数据适合使用缓存,什么样得数据不适合使用缓存

    • 适用:
      • 经常查询的数据,且不经常改变的数据(账号密码的存储)
      • 数据的正确与否队最终结果影响不大的
    • 不适用:
      • 经常改变的,数据的正确与否堆结果影响很大的。比如:商品的库存,银行的汇率、股市的股价。

一级缓存

他指的是mybatisSqlSession对象的缓存。当我们执行完查询之后,查询的结果会同时存在SqlSession为我们提供的一块区域中,该区域的结构是一个Map。

​ 当我们再次查询同样的结果时,mybatis会先去SqlSession中查询是否存在,存在则直接拿出来。当SqlSession对象消失时,mybatis的一级缓存也就消失了。sqlSession.close();

数据持久层Dao

 

java

代码解读

复制代码

User queryUserById(Integer id);

映射文件的编写UserDao.xml

 

xml

代码解读

复制代码

<select id="queryUserById" resultType="user" parameterType="int"> select * from user where id = #{id} </select>

测试类:

 

java

代码解读

复制代码

public void testCache(){ User user1 = userDao.queryUserById(48); System.out.println("The first query:" + user1); User user2 = userDao.queryUserById(48); System.out.println("The first query:" + user2); }

14.png

 这里我们可以发现,虽在我们调用了两次userDao的QueryUserById方法,但是只执行了一次数据库的交互,这就是mybatis的一级缓存起作用了,因为一级缓存的存在,所以第二次查询时直接从一级缓存中去取,没有再进行数据库的二次交互。

15.png

如果SqlSeesion执行了commit操作(更新)或者关闭,会清空缓存中的信息,避免脏读

清空缓存(sqlSqssion.close)
 

java

代码解读

复制代码

public void testCache(){ User user1 = userDao.queryUserById(48); System.out.println("The first query:" + user1); session.close(); //清空缓存 SqlSession session = factory.openSession(); userDao = session.getMapper(UserDao.class); User user2 = this.userDao.queryUserById(48); System.out.println("The first query:" + user2); }

16.png

数据发生更新(update)
 

java

代码解读

复制代码

public void testCache(){ User user1 = userDao.queryUserById(48); System.out.println("The first query:" + user1); User user = new User(); user.setId(48); user.setUsername("小爱同学"); user.setSex("女"); user.setBirthday(new Date()); user.setAddress("广东深圳"); userDao.updateUser(user); session.commit(); User user2 = this.userDao.queryUserById(48); System.out.println("The second query:" + user2); }

17.png

数据发生变换,update会直接抹除当前数据在缓存中的数据,避免脏读

二级缓存

sqlSessionFactory的缓存
二级缓存的开启:

pojo类必须实现Serializable接口

4.2.3.1 测试二级缓存
  • 第一步 在SqlMapConfig.xml 文件开启二级缓存
 

xml

代码解读

复制代码

<settings> <!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/> </settings>

因为cacheEnabled的取值默认就为true,所以这一步可以省略不配置。为true代表开启二级缓存;为false代表不开启二级缓存。

  • 第二步 配置相关的Mapper映射文件
 

xml

代码解读

复制代码

<mapper namespace="com.xq.dao.UserDao"> <!-- 开启二级缓存的支持 --> <cache></cache>

  • 第三步 配置statement 上面的useCache属性
 

xml

代码解读

复制代码

<select id="findUserById" resultType="user" parameterType="int" useCache="true"> select id,username,birthday,sex ,address from user where id=#{id} </select>

总结:

  • 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
  • 如果二级缓存没有命中,再查询一级缓存
  • 如果一级缓存也没有命中,则查询数据库
  • SqlSession关闭之后,一级缓存中的数据会写入二级缓存

Mybatis注解开发

打开mybatis核心配置文件中的包映射

 

xml

代码解读

复制代码

<mappers> <package name="com.duoduo.dao"/> </mappers>

数据控制层Dao

 

java

代码解读

复制代码

//查询所有 @Select("select * from user") List<User> queryAllUser(); //通过id查询 @Select("select * from user where id = #{id}") User queryUserById(Integer id); /** *添加操作 *@SelectKey注解:查询表中最后新增数据的主键 * keyProperty:实体属性的名称 * keyColumn: 数据表对应字段的名称 * resultType: 属性对应的数据类型 * before: 代表查询的时机,false是在新增之后 * statement: {查询语句} */ @Insert("insert into user(username, birthday, sex, address) VALUES (#{username},#{birthday},#{sex},#{address})") @SelectKey(keyProperty = "id",keyColumn = "id",resultType = Integer.class,before = false,statement = {"select 240308"}) void insertUser(User user); //更新操作的注解 @Update("update user set username = #{username},birthday = #{birthday},sex = #{sex},address = #{address} where id = #{id}") void updateUser(User user); //删除的实现 @Delete("delete from user where id = #{id}") void deleteUserById(Integer id); //实现聚合函数的查询 @Select("select count(id) from user") Integer getCount(); //实现模糊查询 @Select("select * from user where username like #{username}") List<User> queryDimByUsername(String username);

Mybatis注解解决前后字段不一致的问题

 

java

代码解读

复制代码

//id 为resultMap引用的id,唯一 @Results(id = "roleMap",value = { //id字段默认为false ,id = true 代表当前字段是主键字段 @Result(id = true,column = "rid",property = "rid"), @Result(column = "role_name",property = "roleName"), @Result(column = "role_desc",property = "roleDesc") }) @Select("select * from role") List<Role> queryAllRole(); //多次使用直接引用@Results的id @ResultMap("roleMap") @Select("select * from role where RID = #{id}") Role queryRoleByRid(Integer id);

基于注解多表查询一对一查询

在Account类里面维护一个pojo实体user

 

java

代码解读

复制代码

@Data public class Account { private Integer aid; private Integer uid; private Double money; private User user; }

数据持久层Dao

 

java

代码解读

复制代码

public interface UserDao { @Select("select * from user where id = #{id}") User queryUserById(); }

 

java

代码解读

复制代码

public interface AccountDao { /** * 一对一用 one = @one * 参数:select * fetchType :加载类型 FetchType.LAZY 懒加载 * @return */ @Results(id = "accountMap",value = { @Result(id = true,column = "aid",property = "aid"), @Result(column = "uid",property = "uid"), @Result(column = "money",property = "money"), @Result(column = "uid",property = "user", one = @One(select = "com.duoduo.dao.UserDao.queryUserById", fetchType = FetchType.LAZY) ) }) @Select("select * from account") List<Account> queryAllAccount(); }

基于注解多表查询一对多查询

在user类维护一个account集合

 

java

代码解读

复制代码

@Data public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; private List<Account> accounts; }

数据持久层Dao

 

java

代码解读

复制代码

/** * 一对多用 many = @Many * 参数:select * fetchType :加载类型 FetchType.LAZY 懒加载 * @return */ @Results(id = "userMap",value = { @Result(id = true,column = "id",property = "id"), @Result(column = "username",property = "username"), @Result(column = "birthday",property = "birthday"), @Result(column = "sex",property = "sex"), @Result(column = "address",property = "address"), @Result(column = "id",property = "accounts", many = @Many(select = "com.duoduo.dao.AccountDao.queryAccountByUid", fetchType = FetchType.LAZY) ) }) @Select("select * from user") List<User> queryAllUser();

 

java

代码解读

复制代码

@Select("select * from account where UID = #{uid}") List<Account> queryAccountByUid(Integer uid);

基于注解多表查询多对多查询

在Role类维护一个user集合

 

java

代码解读

复制代码

@Data public class Role { private Integer rid; private String roleName; private String roleDesc; private List<User> users; }

数据持久层Dao

 

java

代码解读

复制代码

@Results(id = "roleMap",value = { @Result(id = true,column = "rid",property = "rid"), @Result(column = "role_name",property = "roleName"), @Result(column = "role_desc",property = "roleDesc"), @Result(column = "rid",property = "users", many = @Many(select = "com.duoduo.dao.UserDao.queryUsersById", fetchType = FetchType.LAZY) ) }) @Select("select * from role") List<Role> queryAllRole();

 

java

代码解读

复制代码

@Select("select * from user where id in(select uid from user_role where RID = #{rid})") List<User> queryUsersById(Integer id);

Mybatis逆向工程的搭建

导入插件:

注意mysql驱动版本要和依赖中的一致

 

xml

代码解读

复制代码

<!-- 控制Maven在构建过程中相关配置 --> <build> <!-- 构建过程中用到的插件 --> <plugins> <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 --> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.0</version> <!-- 插件的依赖 --> <dependencies> <!-- 逆向工程的核心依赖 --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.2</version> </dependency> <!-- 数据库连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <!-- MySQL驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.42</version> </dependency> </dependencies> </plugin> </plugins> </build>

创建mybatis的核心配置文件
 

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"> <configuration> <properties resource="db.properties"></properties> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"></transactionManager> <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> </configuration>

创建逆向工程的配置文件

注意:逆向工程的文件名必须是:generatorConfig.xml

MyBatis3Simple: 生成基本的CRUD MyBatis3: 生成带条件的CRUD

 

xml

代码解读

复制代码

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!-- targetRuntime: 执行生成的逆向工程的版本 MyBatis3Simple: 生成基本的CRUD MyBatis3: 生成带条件的CRUD --> <context id="DB2Tables" targetRuntime="MyBatis3Simple"> <!-- 数据库的连接信息 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;characterEncoding=UTF-8&amp;useUnicode=true" userId="root" password="rootroot"> </jdbcConnection> <!-- javaBean的生成策略--> <javaModelGenerator targetPackage="com.duoduo.pojo" targetProject=".\src\main\java"> <!-- 是否生成子包。如果为true com.xq.pojo生成的保姆那个带有层级目录 false com.xq.pojo就是一个包名 --> <property name="enableSubPackages" value="true" /> <!-- 通过数据表字段生成pojo。如果字段名称带空格,会去掉空格 --> <property name="trimStrings" value="true" /> </javaModelGenerator> <!-- SQL映射文件的生成策略 --> <sqlMapGenerator targetPackage="com.duoduo.mapper" targetProject=".\src\main\resources"> <property name="enableSubPackages" value="true" /> </sqlMapGenerator> <!-- Mapper接口的生成策略 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.duoduo.mapper" targetProject=".\src\main\java"> <property name="enableSubPackages" value="true" /> </javaClientGenerator> <!-- 逆向分析的表 --> <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName --> <!-- domainObjectName属性指定生成出来的实体类的类名 --> <table tableName="user" domainObjectName="User"/> </context> </generatorConfiguration>

18.png

执行后的效果

19.png

Mybatis分页插件

导入依赖

 

xml

代码解读

复制代码

<!--分页插件--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency>

在mybatis核心配置文件中导入插件

 

xml

代码解读

复制代码

<!--配置分页插件--> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>

测试类:

 

java

代码解读

复制代码

@Test public void test03() throws Exception{ //开启分页操作 PageHelper.startPage(2,4); List<User> userList = userMapper.selectByExample(null); //创建分页模型对象 PageInfo<User> pageInfo = new PageInfo<>(userList); System.out.println(pageInfo); }

属性解读:

  • pageNum:当前页的页码
  • pageSize:每页显示的条数
  • size:当前页显示的真实条数
  • total:总记录数
  • pages:总页数
  • prePage:上一页的页码
  • nextPage:下一页的页码
  • isFirstPage/isLastPage:是否为第一页/最后一页
  • hasPreviousPage/hasNextPage:是否存在上一页/下一页
  • navigatePages:导航分页的页码数
  • navigatepageNums:导航分页的页码,[1,2,3,4,5]
  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值