将 sql 连接参数写到 properties 里,然后Mybatis 引用。
// jdbc.properties
jdbc.username=root
jdbc.password=Liu01234
jdbc.url=jdbc:mysql://localhost:3306/mydb1?characterEncoding=utf-8
jdbc.driverClass=com.mysql.cj.jdbc.Driver
// mybatis-config.xml 部分代码
<configuration>
<!-- 1. -->
<properties resource="jdbc.properties"></properties>
<!-- 2. 第二种方式 -->
<!-- <properties>-->
<!-- <property name="jdbc.url" value="jdbc:mysql://localhost:3306/mydb1?characterEncoding=utf-8"/>-->
<!-- <property name="jdbc.username" value="root"/>-->
<!-- <property name="jdbc.password" value="Liu01234"/>-->
<!-- <property name="jdbc.driverClass" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- </properties>-->
<environments default="d2">
<environment id="d2">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- ${} 动态参数-->
<property name="driver" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
</configuration>
注意 key 要做混合。
引用实体类带包名,名称太长,可以设置别名。
// mybatis-config.xml 部分代码
<typeAliases>
<!-- 1. 给单独的 实体类 设置别名-->
<!-- <typeAlias type="com.baidu.day.text.entity.Acount" alias="acountAli"></typeAlias> -->
<!-- 2. 给一个包下所有的 实体 设置别名,类名默认首字母小写;也可以通过@Alias在类里修改-->
<package name="com.baidu.day.text.entity"/>
</typeAliases>
// Acount 类部分代码
@Data
@AllArgsConstructor
//@Alias("xxx")
public class Acount {
private Integer id;
}
<!-- 3. Mybatis 自带别名 -->
java.lang.Integer 为 integer 等等。
// IAcountMapper.xml 使用
//原
<select id="getAcountById" parameterType="java.lang.Integer" resultType="com.baidu.day.text.entity.Acount">
select * from t_acount where id = #{id}
</select>
// 别名替换后
<select id="getAcountById" parameterType="integer" resultType="acount">
select * from t_acount where id = #{id}
</select>
主键回填。
数据库设置主键自增后,添加新的数据,获取到这条数据的主键。
// IAcountMapper.xml 部分代码
<!--
1. useGeneratedKeys 是否开启主键回填;keyProperty 赋值的主键,赋值给 acount 的 id,不是数据库。
-->
<!-- <insert id="addAcount" parameterType="acount" useGeneratedKeys="true" keyProperty="id">-->
<!-- insert into t_acount(username,img,balance) values(#{username},#{img},#{balance})-->
<!-- </insert>-->
<!--
2. order,插入之前还是之后执行;keyProperty,语句执行后得到值赋给主键;resultType,语句执行后得到值的类型。
-->
<insert id="addAcount" parameterType="acount">
<selectKey order="AFTER" keyProperty="id" resultType="java.lang.Integer">
select last_insert_id()
</selectKey>
insert into t_acount(username,img,balance) values(#{uname},#{img},#{balance})
</insert>
<!--
3. 不支持主键自增的数据库,获取主键方式。
在插入语句执行之后,生成字符串赋值给 id
-->
<insert id="addAcount" parameterType="acount">
<selectKey order="BEFORE" keyProperty="id" resultType="integer">
SELECT REPLACE(UUID(),'-','');
</selectKey>
INSERT into t_user (id,username,password) values(#{id},#{username},#{password});
</insert>
// 测试代码
@Test
public void add() {
Acount acount = new Acount(null,"zs","xx.png",30.0);
SqlSession sqlSession = MybatisUtils.getSqlSession();
System.out.println(acount);
IAcountMapper acountMapper = sqlSession.getMapper(IAcountMapper.class);
int sql = acountMapper.addAcount(acount);
System.out.println(sql);
// 主键回填之后的 acount
System.out.println(acount);
sqlSession.commit();
sqlSession.close();
}
解决当数据库的列名和实体类的属性名不一致问题。
比如列名为username,实体类为uname。
// Acount.java
@Data
@AllArgsConstructor
public class Acount {
private Integer id;
// private String username;
// 数据库列名和实体属性名不一致
private String uname;
private String img;
private Double balance;
}
// IAcountMapper.xml 只是部分代码
// extends="",有大部分重复定义用继承。
<resultMap id="userResultMap" type="acount">
<!-- column 数据库列;property 实体属性 ;只需要写上不一致的字段就行 -->
<!-- 主键用 id 标签,其他用 result -->
<!-- <id column="id" property="id"></id>-->
<result column="username" property="uname"/>
</resultMap>
<!--
这里用了 resultType="acount",是因为上面只定义了不一致的字段。
如果换成 resultMap="userResultMap",则上面的定义要写完全,否则没定义的字段为 null
-->
<select id="getAcountById" parameterType="java.lang.Integer" resultType="acount">
select * from t_acount where id = #{id}
</select>
ORM 映射关系。
Mybatis 分两种,对一和对多关系。
我使用的数据库表。
一对一。
// Emp.java
@Data
public class Emp {
private Integer empno; // 编码
private String ename; // 姓名
private Integer deptno; //部门编号
private Double sal; // 公司
private Double comm; // 奖金
private Integer mgr; // 领导编号
private Date hiredate; // 入职时间
private String job; // 职位
// 在员工对象里存储领导对象
private Emp mgrEmp; // 领导对象
}
// IEmpMapper.java
public interface IEmpMapper {
public Emp getEmpByEmpno(Integer empno);
}
// IEmpMapper.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.baidu.day.text.mapper.IEmpMapper">
<resultMap id="empResultMap" type="emp">
<id column="empno" property="empno"/>
<result column="ename" property="ename"/>
<result column="job" property="job"/>
<result column="sal" property="sal"/>
<result column="comm" property="comm"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hiredate"/>
<result column="deptno" property="deptno"/>
<!--
员工和领导 一对一 关系 ,员工 emp 里有领导 emp 对象
多表中存在相同列名的时候可以通过别名来解决
property 实体属性
javaType 实体属性的类型
-->
<association property="mgrEmp" javaType="emp">
<id column="mempno" property="empno" />
<result column="mename" property="ename" />
<result column="mjob" property="job" />
</association>
</resultMap>
<!--
resultMap="empResultMap", 如果不写基本映射关系会为空
resultType="emp" mgrEmp映射会为空,
-->
<select id="getEmpByEmpno" parameterType="java.lang.Integer" resultMap="empResultMap">
select
e.*,
m.empno as mempno,
m.ename as mename,
m.job as mjob
from emp e inner join emp m on (e.mgr = m.empno)
where e.empno = #{empno}
</select>
</mapper>
// MybatisTest.java 测试
public class MybatisTest {
@Test
public void testShow() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
// mapper 写法
IEmpMapper empMapper = sqlSession.getMapper(IEmpMapper.class);
Emp emp = empMapper.getEmpByEmpno(7369);
System.out.println(emp);
sqlSession.close();
}
}
多对一。
@Data
public class Emp {
private Integer empno; // 编码
private String ename; // 姓名
private Integer deptno; //部门编号
private Double sal; // 公司
private Double comm; // 奖金
private Integer mgr; // 领导编号
private Date hiredate; // 入职时间
private String job; // 职位
private Dept dept; // 员工对应的部门信息
}
@Data
public class Dept {
private Integer deptno;
private String dname;
private String loc;
}
public interface IEmpMapper {
// 查询所有的员工,要求员工的属性中包含部门信息
public List<Emp> getEmpList();
}
// IEmpMapper.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.baidu.day.text.mapper.IEmpMapper">
<resultMap id="empResultMap" type="emp">
<!-- 基本映射 -->
<id column="empno" property="empno"/>
<result column="ename" property="ename"/>
<result column="job" property="job"/>
<result column="sal" property="sal"/>
<result column="comm" property="comm"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hiredate"/>
<result column="deptno" property="deptno"/>
<!--
员工和部门 多对一 关系,多个员工属于一个部门
-->
<association property="dept" javaType="dept">
<id column="deptno" property="deptno" />
<result column="dname" property="dname" />
<result column="loc" property="loc" />
</association>
</resultMap>
<select id="getEmpList" resultMap="empResultMap">
select
e.*,
d.*
from emp e inner join dept d on (e.deptno = d.deptno)
</select>
</mapper>
// 测试类
public class MybatisTest {
@Test
public void testShow() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
// mapper 写法
IEmpMapper empMapper = sqlSession.getMapper(IEmpMapper.class);
List<Emp> empList = empMapper.getEmpList();
for (Emp emp : empList) {
System.out.println(emp);
}
sqlSession.close();
}
}
一对多。
@Data
public class Dept {
private Integer deptno;
private String dname;
private String loc;
private List<Emp> empList; // 保存部门下的所有员工
}
@Data
public class Emp {
private Integer empno; // 编码
private String ename; // 姓名
private Integer deptno; //部门编号
private Double sal; // 公司
private Double comm; // 奖金
private Integer mgr; // 领导编号
private Date hiredate; // 入职时间
private String job; // 职位
// private Emp mgrEmp; // 领导对象
private Dept dept; // 员工对应的部门信息
}
public interface IDeptMapper {
public Dept getDeptByDeptno(Integer deptno);
}
//IDeptMapper.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.baidu.day.text.mapper.IDeptMapper">
<resultMap id="deptResultMap" type="dept">
<!-- 基本映射 -->
<id column="deptno" property="deptno"/>
<result column="dname" property="dname"/>
<result column="loc" property="loc"/>
<!--
部门和员工 一对多 关系
ofType 集合存储的类型,非集合
-->
<collection property="empList" ofType="emp">
<id column="empno" property="empno"/>
<result column="ename" property="ename" />
<result column="job" property="job"/>
<result column="sal" property="sal"/>
<result column="comm" property="comm"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hiredate"/>
<result column="deptno" property="deptno"/>
<!-- 可以套娃 员工对部门 多 对 一 -->
<association property="dept" javaType="dept">
<id column="deptno" property="deptno"/>
<result column="dname" property="dname"/>
<result column="loc" property="loc"/>
</association>
</collection>
</resultMap>
<select id="getDeptByDeptno" resultMap="deptResultMap">
select
d.*,
e.*
from dept d inner join emp e on (d.deptno = e.deptno)
where d.deptno = #{deptno}
</select>
</mapper>
public class MybatisTest {
@Test
public void testShow() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
// mapper 写法
IDeptMapper deptMapper = sqlSession.getMapper(IDeptMapper.class);
Dept dept = deptMapper.getDeptByDeptno(10);
System.out.println(dept);
for (Emp emp : dept.getEmpList()) {
System.out.println(emp);
}
sqlSession.close();
}
}
mapper 接收参数问题。
注意 #{arg1} 是占位符,数据库语句会预编译。占位符只能占位 value,不能占位 key。像查询语句,占位 key 值,不会返回数据。这时要使用 ${arg1},直接注入。
如:
// 方法
public Emp findEmpByEmpno(Emp emp);
// mapper
<select id="findEmpByEmpno" parameterType="emp" resultType="emp">
select #{ename},#{job} from emp where empno = #{empno}
// 或
select ${ename},${job} from emp where empno = ${empno}
</select>
// 测试
Emp emp = new Emp();
emp.setEname("ename");
emp.setJob("job");
emp.setEmpno(7369);
Emp empRes = empMapper.findEmpByEmpno(emp);
System.out.println(empRes);
区别如图:
普通的传参方法,实际上跟参数名没有关系。
// 方法
public Emp getEmpByEmpno(Integer empno);
// mapper
<select id="getEmpByEmpno" resultType="emp">
select * from emp where empno = #{ddasdfsdfaasdfd}
</select>
// 测试
@Test
public void testGetEmpByEmpno() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
IEmpMapper empMapper = sqlSession.getMapper(IEmpMapper.class);
Emp empRes = empMapper.getEmpByEmpno(7369);
System.out.println(empRes);
}
// 打印,可以看到同样可以获取值
2021-01-16 17:07:32 DEBUG com.baidu.day.text.mapper.IEmpMapper.getEmpByEmpno {0}: 159 - ==> Preparing: select * from emp where empno = ?
2021-01-16 17:07:32 DEBUG com.baidu.day.text.mapper.IEmpMapper.getEmpByEmpno {0}: 159 - ==> Parameters: 7369(Integer)
2021-01-16 17:07:32 DEBUG com.baidu.day.text.mapper.IEmpMapper.getEmpByEmpno {0}: 159 - <== Total: 1
Emp(empno=7369, ename=SMITH, deptno=20, sal=800.0, comm=null, mgr=7902, hiredate=Wed Dec 17 14:00:00 CST 1980, job=CLERK)
mapper 接收参数有三种方式。一种是封装成对象(前面写过了)或map,一种是采用注解 @Param(“emp”);,一种是 ${arg1} 。
// 1.
// 方法
public Emp findEmpByEmpno(Integer empno, String column);
// mapper
select ${arg1} from emp where empno = ${arg0}
select ${param2} from emp where empno = ${param1}
// 2.
// 方法
public Emp findEmpByEmpno(@Param("empno") Integer empno,@Param("column") String column);
// mapper
select ${column} from emp where empno = #{empno}
// 3.
// 方法
public Emp findEmpByEmpno(Map<String, Object> map);
// mapper
select ${ename},${job} from emp where empno = ${empno}
// 测试
Map<String, Object> map = new HashMap<>();
map.put("ename","ename");
map.put("job","job");
map.put("empno",7369);
Emp empRes = empMapper.findEmpByEmpno(map);
System.out.println(empRes);
${arg1} 直接注入语句可以很灵活的控制接收。但要注意安全问题。
// 方法
public List<Map<String,Object>> findQuery(@Param("sql") String sql);
// mapper
<select id="findQuery" resultType="map">
${sql}
</select>
// 测试
@Test
public void testFindQuery(){
IEmpMapper mapper = MyBatisUtils.getSqlSession().getMapper(IEmpMapper.class);
List<Map<String, Object>> list= mapper.findQuery("select dname,loc from dept");
for (Map<String, Object> map : list) {
System.out.println(map);
}
}
MyBatis 内数据库条件判断标签的使用。
代码结构。有一部分没改动的代码我就不贴出来了。
public interface IEmpMapper {
public List<Emp> getEmpList();
public Emp getEmpByEmpno(Integer empno);
public List<Emp> findEmp(Emp emp);
public int update(Emp emp);
public int batchDel(List<Integer> ids);
}
// IEmpMapper.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.baidu.day.text.mapper.IEmpMapper">
<!-- 提取公共部分 -->
<sql id="base_emp">
empno,
ename,
job,
sal,
comm,
hiredate,
mgr,
deptno
</sql>
<select id="getEmpList" resultType="emp">
select
<include refid="base_emp" />
from emp
</select>
<select id="getEmpByEmpno" resultType="emp">
select
<include refid="base_emp" />
from emp where empno = #{empno}
</select>
<!--
where 标签,条件匹配并且自动删除多余 and
<![CDATA[ ]]>,包装关键符号
-->
<!--
<select id="findEmp" resultType="emp">
select
<include refid="base_emp"></include>
from emp
<where>
<if test="ename != null and ename != ''">
and ename like concat("%",#{ename},"%")
</if>
<if test="deptno != null">
and deptno = #{deptno}
</if>
<if test="sal != null">
<![CDATA[
and sal < #{sal}
]]>
</if>
</where>
</select>
-->
<!--
set 标签,条件匹配并且自动删除多余 ,
-->
<!--
<update id="update">
update emp
<set>
<if test="ename != null and ename != ''">
ename = #{ename},
</if>
<if test="sal != null">
sal = #{sal},
</if>
<if test="job != null">
job = #{job},
</if>
</set>
<where>
empno = #{empno}
</where>
</update>
-->
<!--
trim 标签,包装了 set 和 where;
suffixOverrides 删除多余的后置字符;
prefixOverrides 删除多余的前置字符
-->
<select id="findEmp" resultType="emp">
select
<include refid="base_emp" />
from emp
<trim prefix="where" prefixOverrides="and">
<if test="ename != null and ename != ''">
and ename like concat("%",#{ename},"%")
</if>
<if test="deptno != null">
and deptno = #{deptno}
</if>
<if test="sal != null">
<![CDATA[
and sal < #{sal}
]]>
</if>
</trim>
</select>
<update id="update">
update emp
<trim prefix="set" suffixOverrides=",">
<if test="ename != null and ename != ''">
ename = #{ename},
</if>
<if test="sal != null">
sal = #{sal},
</if>
<if test="job != null">
job = #{job},
</if>
</trim>
<where>
empno = #{empno}
</where>
</update>
<!--
foreach 标签
collection 遍历集合
open:第一次遍历的时执行
close:最后一次遍历执行
item:当前遍历的对象,类似var
index: 遍历的索引,从0开始
separator:分隔符,每遍历一次都会执行
-->
<delete id="batchDel">
delete from emp where empno in
<!--
(7902,7934)
-->
<foreach collection="list" open="(" close=")"
item="id" separator="," index="index">
#{id}
</foreach>
</delete>
</mapper>
// 测试类
package com.baidu.day.text.mapper;
import com.baidu.day.text.entity.Emp;
import com.baidu.day.text.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class IEmpMapperTest {
@Test
public void getEmpList() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
IEmpMapper mapper = sqlSession.getMapper(IEmpMapper.class);
List<Emp> empList = mapper.getEmpList();
for (Emp emp : empList) {
System.out.println(emp);
}
sqlSession.close();
}
@Test
public void getEmpByEmpno() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
IEmpMapper mapper = sqlSession.getMapper(IEmpMapper.class);
Emp empRes = mapper.getEmpByEmpno(7369);
System.out.println(empRes);
sqlSession.close();
}
@Test
public void findEmp() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
IEmpMapper mapper = sqlSession.getMapper(IEmpMapper.class);
Emp empOb = new Emp();
empOb.setDeptno(10);
List<Emp> empList = mapper.findEmp(empOb);
for (Emp emp : empList) {
System.out.println(emp);
}
sqlSession.close();
}
@Test
public void update() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
IEmpMapper mapper = sqlSession.getMapper(IEmpMapper.class);
Emp emp = new Emp();
emp.setEmpno(7499);
emp.setEname("ALLEN1");
int i = mapper.update(emp);
System.out.println(i);
sqlSession.commit();
sqlSession.close();
}
@Test
public void batchDel() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
IEmpMapper mapper = sqlSession.getMapper(IEmpMapper.class);
List<Integer> list = new ArrayList<>();
list.add(7902);
list.add(7934);
int i = mapper.batchDel(list);
System.out.println(i);
sqlSession.commit();
sqlSession.close();
}
}