Mybatis -- 使用
官网
入门_MyBatis中文网
依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- mysql 连接 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
引入Logback
Logback -- 使用_naki_bb的博客-CSDN博客
简单使用
配置文件目录结构
mybatis-config.xml -- 数据库连接以及Mappers信息
<?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:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
UserMapper.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="test">
<select id="selectAll" resultType="com.lb.pojo.User">
select * from tb_user;
</select>
</mapper>
测试:
public class MybatisDemo {
public static void main(String[] args) throws IOException {
//加载mybatis配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过UserMapper.xml中的namespace和id,调用对应的sql
List<User> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
//关闭sqlSession
sqlSession.close();
}
}
通过入门已经可以使用的mybatis了,但是当Mapper过多时,每个都要添加,以及根据namespace的调用,不是很方便,则使用Mapper代理方式简化配置,以及方法调用
Mapper代理方式
注意事项:
1.定义与SQL映射文件同名的Mapper接口,并且Mapper接口和SQL映射文件放置在同一目录下
Mapper接口的目录需要和Mapper.xml文件目录一致,并且Resouce下创建文件不能使用“.”分割需要使用文件分隔符,否则编译完成,文件没有在同一目录下
2.SQL映射文件的namespace属性为Mapper接口的全限定名
3.在Mapper接口中定义方法,方案名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致
4.如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL文件的加载
全部配置如下:
public interface UserMapper {
List<User> selectAll();
User selectById(Integer id);
}
mybatis-config.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>
<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:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--
<mapper resource="com/lb/mapper/UserMapper.xml"/>
-->
<!-- 直接包扫描 -->
<package name="com.lb.mapper"/>
</mappers>
</configuration>
UserMapper.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.lb.mapper.UserMapper">
<select id="selectAll" resultType="com.lb.pojo.User">
select * from tb_user;
</select>
<select id="selectById" parameterType="Integer" resultType="com.lb.pojo.User">
select * from tb_user where id = #{id};
</select>
</mapper>
测试:
public class MybatisDemo {
public static void main(String[] args) throws IOException {
//加载mybatis配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.selectAll();
User user = mapper.selectById(1);
System.out.println(users);
System.out.println(user);
//关闭sqlSession
sqlSession.close();
}
}
字段属性名映射
当数据库列名与对象属性名称不一致时,建立映射关系
@Data
public class Brand {
private Integer brandId;
private String brandName;
private String companyName;
private String ordered;
private String description;
private String status;
}
<?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.lb.mapper.BrandMapper">
<resultMap id="brandResultMap" type="com.lb.pojo.Brand">
<!-- 设置列名和字段名的匹配 -->
<!-- id映射-->
<id column="id" property="brandId"/>
<!-- 普通列映射 -->
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<select id="selectAll" resultMap="brandResultMap">
select * from tb_brand;
</select>
</mapper>
返回类型 从resultType 替换 成 resultMap
请求参数
1.普通类型参数
Brand selectByBrandId(int id);
<!--
根绝参数进行查询
parameterType可以省略不写
#{} -> 在生成sql时会替换成 ?
${} -> 在生成sql时会直接拼接到sql上,会有sql注入的风险
如果在表名或者列名不确定时, 可以使用直接拼接sql
-->
<select id="selectByBrandId" parameterType="int" resultMap="brandResultMap">
select * from tb_brand where id = #{id};
</select>
2.多个参数
List<Brand> selectByParameter(
@Param("status") int status,
@Param("brandName") String brandName,
@Param("companyName") String companyName);
@Param 的 value 和 sql中的参数名必须一致
<select id="selectByParameter" resultMap="brandResultMap">
select * from tb_brand where
status = #{status}
and brand_name like #{brandName}
and company_name like #{companyName}
</select>
3.对象参数
List<Brand> selectByBrand(Brand brand);
对象的属性名必须和sql中的参数名一致
<select id="selectByBrand" resultMap="brandResultMap">
select * from tb_brand where
status = #{status}
and brand_name like #{brandName}
and company_name like #{companyName}
</select>
4.Map参数
Map map = new HashMap();
map.put("status",status);
map.put("brandName",brandName);
map.put("companyName",companyName);
List<Brand> selectByMap(Map map);
<select id="selectByMap" resultMap="brandResultMap">
select * from tb_brand where
status = #{status}
and brand_name like #{brandName}
and company_name like #{companyName}
</select>
动态参数
IF 判断
<select id="selectByBrand" resultMap="brandResultMap">
select * from tb_brand
where
<if test="status != null">
status = #{status}
</if>
<if test="brandName != null and brandName != ''">
and brand_name like #{brandName}
</if>
<if test="companyName != null and companyName != ''">
and company_name like #{companyName}
</if>
</select>
上面的sql,可以根据参数值是否存在动态的拼接sql,当除了status没值外,都可以正常运行。
当status没值时,报错,生成的sql如下
因为where后的第一个参数不能带有and,所以需要使用<where> 标签来优化,它可以动态检查,看是否需要添加 and 关键字,需要给每一个参数添加 and 关键字
<select id="selectByBrand" resultMap="brandResultMap">
select * from tb_brand
<where>
<if test="status != null">
and status = #{status}
</if>
<if test="brandName != null and brandName != ''">
and brand_name like #{brandName}
</if>
<if test="companyName != null and companyName != ''">
and company_name like #{companyName}
</if>
</where>
</select>
Choose判断
单一条件成立类似于Java 中的 switch
<select id="selectByBrandSingle" resultMap="brandResultMap">
select * from tb_brand
<where>
<choose> <!-- when条件只会有一个执行 -->
<when test="status != null">
status = #{status}
</when>
<when test="brandName != null and brandName != ''">
brand_name like #{brandName}
</when>
<when test="companyName != null and companyName != ''">
company_name like #{companyName}
</when>
<!-- 都不成立时
<otherwise></otherwise>
-->
</choose>
</where>
</select>
当参数都有值时,也会按照顺序判断,走第一个满足的条件。
特殊字符
在xml中 < 是特殊字符
解决方法:
1.转义字符 <
2. <![CDATA[内容]]>
插入insert
void addBrand(Brand brand);
<insert id="addBrand" useGeneratedKeys="true" keyProperty="brandId">
insert into tb_brand (brand_name, company_name, ordered, description, status) values
(#{brandName},#{companyName},#{ordered},#{description},#{status});
</insert>
注意
要添加 useGeneratedKeys="true" keyProperty="brandId" 设置ID回填,并且设置id的属性名.
在获取sqlSession时,sqlSessionFactory.openSession默认是手动提交事务,所以insert后需要手动提交,所以
SqlSession sqlSession = sqlSessionFactory.openSession(true);
使用以上获取sqlSession设置自动提交为true。则不需要手动提交事务。
更新update
/**
* @return 影响的行数
*/
int updateBrand(Brand brand);
<update id="updateBrand">
update tb_brand
<set>
<if test="brandName != null and brandName != ''">
brand_name = #{brandName},
</if>
<if test="companyName != null and companyName != ''">
company_name = #{companyName},
</if>
<if test="ordered != null and ordered != ''">
ordered = #{ordered},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="status != null">
status = #{status},
</if>
<if test="brandId != null">
id = #{brandId},
</if>
</set>
where id = #{brandId}
</update>
update可能参数为空,所以使用if标签动态添加,多余的“," set标签会处理。
为什么我的例子中set标签中会添加一个set id的 if标签,是为了防止当除了id以外其他的所有属性都不存在时,生成update tb_brand where id = ?这个sql,会到报错。所以设置一个恒等的标签,即使所有属性都为空,也不会报错。
删除delete
单个删除
// 返回值为删除的个数
int deleteByBrandId(int id);
<delete id="deleteByBrandId">
delete from tb_brand where id = #{id} ;
</delete>
多个删除
使用循环foreach,如果不使用@Param进行变量命名的化,sql直接写ids是不识别的,mybatis默认的变量名为array,所以如果不适用@Param则使用array来接受数组参数
//返回值是删除的个数
int deleteByIds(@Param("ids") int[] ids);
<delete id="deleteByIds">
delete from tb_brand
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
参数封装
单个参数
1.POJO 类型: 直接使用,属性名 和参数占位符名称一致
2.Map集合:直接使用,键名 和 参数占位符名称一致
3.Collection: 封装成Map集合,可以使用@Param 注解,替换Map集合默认的arg键名
map.put("arg0",collection集合);
map.put("collection",collection集合)
4.List: 封装成Map集合,可以使用@Param 注解,替换Map集合默认的arg键名
map.put("arg0",list集合);
map.put("collection",list集合)
map.put("list",list集合)
5.Array:封装成Map集合,可以使用@Param 注解,替换Map集合默认的arg键名
map.put("arg0",数组);
map.put("array",数组)
6.其他类型,直接使用
多个参数
封装成Map集合,可以使用@Param 注解,替换Map集合默认的arg键名
map.put("arg0",参数1);
map.put("param1",参数1);
map.put("arg1",参数2);
map.put("param2",参数2);
--------------------------------------@Param("username")
map.put("username",参数1);
map.put("param1",参数1);
map.put("arg1",参数2);
map.put("param2",参数2);
一对一查询
@Data
public class Employee {
private Integer id;
private String name;
private String gender;
private Dept dept;
}
@Data
public class Dept {
private Integer id;
private String name;
}
public interface EmployeeMapper {
List<Employee> selectAll();
}
<?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.lb.mapper.EmployeeMapper">
<resultMap id="employeeResultMap" type="com.lb.pojo.Employee">
<!-- 如果包含association标签,即使其他属性和列名一致,也需要声明,否则映射不到 -->
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="gender" column="gender"></result>
<!--
association 这个标签对应employee中的dept成员变量属性
-->
<association property="dept" javaType="com.lb.pojo.Dept">
<id property="id" column="dept_id"></id>
<result property="name" column="dept_name"></result>
</association>
</resultMap>
<select id="selectAll" resultMap="employeeResultMap">
select e.*, d.id dept_id, d.name dept_name from tb_emp e, tb_dept d where e.dept_id = d.id
</select>
</mapper>
注意
如果resultMap包含association标签,即使其他属性和列名一致,也需要声明,否则映射不到
一对多查询
@Data
public class Dept {
private Integer id;
private String name;
List<Emp> employees;
}
@Data
public class Emp {
private Integer id;
private String name;
private String gender;
}
public interface DeptMapper {
List<Dept> selectAll();
}
<?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.lb.mapper.DeptMapper">
<resultMap id="deptResultMap" type="com.lb.pojo.Dept">
<id property="id" column="dept_id"/>
<result property="name" column="dept_name"/>
<collection property="employees" ofType="com.lb.pojo.Emp">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="gender" column="gender"/>
</collection>
</resultMap>
<select id="selectAll" resultMap="deptResultMap">
select d.id dept_id, d.name dept_name, e.* from tb_emp e, tb_dept d where e.dept_id = d.id
</select>
</mapper>
注意collection 使用的是ofType属性。
注解方式执行SQL
注解的方式只能执行一些简单的sql,如果sql比较复杂还是推荐使用xml的方式进行书写,如果使用注解会产生sql复杂,不易阅读,不易书写等诸多问题
@Select("select * from tb_user where username = #{name}")
User selectByName(String name);
@Insert("insert into tb_user values(null,#{username},#{password},#{gender},#{addr})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(User user);
@Update("update tb_user set username = #{username} where id = #{id}")
int updateUserName(@Param("username") String username, @Param("id") int id);
@Delete("delete from tb_user where id = #{id}")
int delete(int id);
Idea 辅助工具
1.连接数据库
2.安装MybatisX 插件 -- 方便开发
3.取消mapper.xml中的黄色以及绿色背景
去掉IDEA生成的mapper.xml中黄色和绿色的背景_一只小程序员啊的博客-CSDN博客_idea xml去掉绿色背景
整合Springboot
SpringBoot 整合 Mybatis_naki_bb的博客-CSDN博客