学习Mybatis框架的使用
1. 快速上手
- Mybatis框架作用:是一款持久层框架,减轻在JavaWeb基础时进行JDBC数据库的CRUD操作,可以直接进行实体类与数据库的关系映射
- 使用Mybatis需要的jar包:数据库驱动包(这里使用Mysql),Mybatis包,Junit(测试程序需要的包) maven依赖
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies>
- 根据官网:
https://mybatis.org/mybatis-3/zh/getting-started.html
- 写mybatis-config.xml配置文件,从 XML 中构建 SqlSessionFactory(可以产生执行Sql的对象)
<?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="${driver}"/>
<property name="url" value="jdbc:mysql://localhost:3306/mysql_test?useSSL=true&useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
- 创建需要操作的数据表对应的实体类(poji),字段和属性名一一对应,类型也要一样,然后创建操作实体类对应的接口UserMapper,这里不需要实现类,需要与之对应的xml文件(相当于实现类)UserMapper.xml,需要在主配置文件中注册。
这里的namespace与接口的全限类名一样,每个id对应接口中的方法名
public interface UserMapper {
List<User> selectUser();
}
<?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.UserMapper">
<select id="selectUser" resultType="返回类型的全限的类名">
select * from User
</select>
</mapper>
- 从 SqlSessionFactory 中获取 SqlSession,执行sql,返回结果
SqlSession session = sqlSessionFactory.openSession()
UseMapper mapper = session.getMapper(UseMapper.class);
List<User> users= mapper.selectUser();
2.实现增删改查操作(增删改操作需要提交事务)
- 在快速入门的时候,已经写好了mybatis-config.xm,并将UserMapper.xml进行注册,也写好了pojo实体类,与之对应的接口UserMapper。
- 现在实现一个插入数据库的操作,只需要修改 UserMapper.xml 和 接口UserMapper
- 实现插入一个用户的操作,在 UserMapper.xml中,标签insert ,parameterType=“传入的参数类型,自定义对象需要全限类名”
<!-- id为接口的方法名 传入对象 键为属性值 使用#{属性值}取值 -->
<insert id="insertUser" parameterType="com.User">
insert into user(`name`,gradeid,gender) VALUES (#{name},#{gradeid},#{gender})
</insert>
- 修改操作同理,只需要在接口中添加一个方法,和在 UserMapper.xml 中配置sql就可以啦
<update id="updateById" parameterType="com.xxx.pojo.User">
update user set `name`=#{name},gender=#{gender} where id=#{id};
</update>
- 删除操作同理,只需要在接口中添加一个方法,和在 UserMapper.xml 中配置sql就可以啦
<delete id="deleteById" parameterType="int">
delete from user where id=#{id}
</delete>
public interface UserMapper {
// 查询所有数据
List<User> selectUser();
// 插入一条数据
int insertUser(User user);
// 根据id修改值
int updateById(User user);
// 根据id删除一条数据
int deleteById(int id);
}
3.参数可以传递Map,直接取键就行了 , 实现分页
<!-- 传入的类型为Map,按键取值就行 -->
<update id="updateMap" parameterType="map">
update user set `name`=#{mapname},gender=#{mapgender} where id=#{mapid};
</update>
分页操作可以传递map:
第一种使用map:
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Integer> map = new HashMap<String, Integer>();
map.put("startIndex",5);
map.put("pageSize",5);
List<User> users = mapper.selectUserLimit(map);
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
<select id="selectUserLimit" parameterType="map" resultType="user">
select * from user limit #{startIndex},#{pageSize}
</select>
第二种在Java层面进行分页,还是查询全部: 一定要使用原始的方法:sqlSession.selectList , 传入分页的对象
SqlSession sqlSession = MybatisUtil.getSqlSession();
RowBounds rowBounds = new RowBounds(0, 6);
List<User> users = sqlSession.selectList("com.xxx.Dao.UserMapper.selectUser", null, rowBounds);
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
<select id="selectUser" resultType="user">
select * from user
</select>
<!-- 模糊查询 -->
<select id="selectUserLike" resultType="com.xxx.pojo.User">
select * from user where name LIKE "%王%"
</select>
4.Mybatis核心配置文件的解析
- 配置数据库连接的环境,默认使用JDBC(有事务),POOLED(连接池),可以配置多套数据环境,但每个 SqlSessionFactory 实例只能使用一种
- 可以使用 引用外部的配置文件,
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置
但是如果重名外部配置文件的会使用(覆盖掉内部的)
<properties resource="db.properties">
<property name="password" value="jkj"/>
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
- 起别名
有两种方式 一种指定别名,一种扫描包,别名默认为为首字母小写的类名,可以使用注解起别的@Alias(“别名”)
<typeAliases>
<typeAlias type="类的全限名" alias="别名"/>
<typeAlias type="com.xxx.pojo.User" alias="User"/>
</typeAliases>
<typeAliases>
<package name="实体类所在的包的路径"/>
<package name="com.xxx.pojo"/>
</typeAliases>
- Mapper 映射器
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<!-- 如果使用配置文件需要将配置文件和接口放在同一文件中且同名 -->
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<!-- 如果使用配置文件需要将配置文件和接口放在同一文件中且同名 -->
<package name="org.mybatis.builder"/>
</mappers>
- settings中配置日志输出
https://blog.csdn.net/sinat_30185177/article/details/73550377
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/> 可以直接打印在控制台
<setting name="logImpl" value="LOG4J"/> 需要配置文件 log4j.properties
</settings>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
5. resultMap 解决实体类属性名和数据库字段名不一致问题
- 可以在查询时起别名
<select id="selectUser" resultType="user">
select id,name,gradeid,gender as sex from user
</select>
- 使用resultMap ,可以只写不一致的那个字段
<resultMap id="userType" type="User">
<result column="gender" property="sex"/>
</resultMap>
<select id="selectUser" resultMap="userType">
select * from user
</select>
6. 使用注解
- 增删改查的注解 @Insert,@Update,@Delete,@Select
@Insert("insert into user(name,gradeid,gender) values(#{name},#{gradeid},#{sex})")
int InsertUser(User user);
- 多个参数使用注解@Param(“参数名”)
User selectUserById(@Param("uid") int id); // 会使用注解内的参数名
- 注解和配置文件可以一起使用,但对于同一个方法只能选择一个
参考别人的博客:
https://blog.csdn.net/liangcheng0523/article/details/106882135/
7.多对一查询(实体类中有对象)
public class User {
private int id;
private String name;
private String gender;
private Grade grade;
}
public class Grade {
private int id;
private String grade;
}
<mapper namespace="com.xxx.Dao.UserMapper">
<resultMap id="userGrade" type="user">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="gender" column="gender"/>
<!-- property是属性 column是字段 javaType表示属性对应的类型 select表示根据哪条sql查询,依靠字段column="gradeid",也是select="selectGrade"查询语句的参数 -->
<association property="grade" column="gradeid" javaType="grade" select="selectGrade"/>
</resultMap>
<select id="selectUser" resultMap="userGrade">
select * from user
</select>
<!-- 子查询形式实现 -->
<select id="selectGrade" resultType="grade">
select * from grade where id=#{gradeid}
</select>
</mapper>
<!--===========================================================================-->
<!-- 结果集嵌套映射实现 -->
<resultMap id="userGrade2" type="user">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="gender" column="gender"/>
<!-- property表示实体类User中的对象属性 javaType表示属性的类型(没有起别名就写全限类名) -->
<association property="grade" javaType="grade">
<!-- property 表示Grade实体类的普通属性 column表示查询结果中 字段对应的值 -->
<result property="grade" column="grade"/>
<result property="id" column="gid"/>
</association>
</resultMap>
<!-- 联表查询 -->
<select id="selectUser2" resultMap="userGrade2">
select u.id,u.name,u.gender,g.grade,g.id gid from user u,grade g where u.gradeid=g.id
</select>
8.一对多(实体类有集合)
public class User {
private int id;
private String name;
private String gender;
private int grideid;
}
public class Grade {
private int id;
private String grade;
// 一对多的列表集合
private List<User> users;
}
<!-- 结果集嵌套映射 -->
<mapper namespace="xxx.Dao.GradeMapper">
<resultMap id="gradeUser" type="grade">
<result property="id" column="gid"/>
<result property="grade" column="grade"/>
<!-- 列表的类型使用 ofType 其实和javaType作用相同 -->
<collection property="users" ofType="user">
<result property="id" column="uid"/>
<result property="name" column="name"/>
<result property="gender" column="gender"/>
<result property="grideid" column="gid"/>
</collection>
</resultMap>
<select id="getGradeList" resultMap="gradeUser">
select u.id uid,u.name,u.gender,g.id gid,g.grade from user u,grade g where u.gradeid=g.id;
</select>
<!-- ============================================================================= -->
<!-- 子查询形式 -->
<resultMap id="grades" type="grade">
<result property="id" column="id"/>
<result property="grade" column="grade"/>
<collection property="users" ofType="user" column="id" select="selectByGradeId"/>
</resultMap>
<select id="gradeUser2" resultMap="grades">
select * from grade
</select>
<select id="selectByGradeId" resultType="user">
select * from user where gradeid=#{id}
</select>
</mapper>
9.动态SQL 其中test中直接写键(传入的参数)不用 #{}/${}进行取值(好像会自动对键(传入的参数)进行取值再判断)
- if test必填,作为条件判断,若条件满足则添加包含的语句
<resultMap id="providerMap" type="smbmsProvider">
<result property="proName" column="proName"/>
<result property="proContact" column="proContact"/>
<result property="proPhone" column="proPhone"/>
<result property="proAddress" column="proAddress"/>
</resultMap>
<select id="selectIf" resultMap="providerMap">
select proName,proContact,proPhone,proAddress from smbms_provider
<where>
<if test="pname != null">
proContact like "%"#{pname}"%"
</if>
</where>
</select>
- choose,when,otherwise 相当于java的switch,case,default 只会选择一句进行插入
<select id="selectChoose" resultMap="providerMap" parameterType="map">
select proName,proContact,proPhone,proAddress from smbms_provider
<where>
<choose>
<when test="proName != null">
and proName like "%"#{proName}"%"
</when>
<when test="proDesc != null">
and proDesc like "%"#{proDesc}"%"
</when>
<otherwise>
and 1==1
</otherwise>
</choose>
</where>
</select>
- trim,where,set
<!-- 等价于where -->
<trim prefix="where" prefixOverrides="and|or">
</trim>
<!-- 等价于set -->
<trim prefix="set" suffixOverrides=",">
</trim>
- foreach
<select id="selectForeach" resultMap="providerMap" parameterType="list">
select proName,proContact,proPhone,proAddress from smbms_provider
<where>
<!-- collection的参数表示键,如果传的是列表使用list,数组使用array,map则写map中可遍历的对象对应的键 例{"ids":[1,2,4,5]},就写ids 其他参数 item 遍历的每个值 open 以什么开始 separator 分隔符 close 以什么结束 -->
<foreach collection="list" item="item" close=")" separator="," open="id in (">
#{item}
</foreach>
</where>
</select>
10.缓存
- Mybatis默认开启一级缓存,即在一个sqlSession的开启和关闭之间存入一级缓存中,也就是在这之间有效,查询同一个Sql则从缓存中读取,不进行连接数据库
- 一级缓存失效: 1.查询同一个sql不同的数据(例如根据id查询,id不同) 2. 清除缓存sqlSession.clearCache();3. 不同的sqlSession
- 二级缓存:在主配置文件的Settings中配置开启缓存cache,然后在每个Mapper.xml中设置cache的属性<cache … />
- 二级缓存在命名空间有效,在同一个mapper的有效,sqlSession关闭则会将一级缓存的数据保存到二级缓存中
- 例如mapper.selectUser() 会先从二级缓存查询,没有则查询一级缓存,在没有则连接数据库查询
- 还可以自定义缓存
Mybatis-config.xml 头文件和Mapper.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>
</configuration>
<?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=" ">
</mapper>
log4j.properties文件
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/a.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG