1.通过dao和映射文件的关联来完成操作---企业开发模式
我们之前使用SqlSession封装的一些方法可以完成crud操作,但是SqlSession封装的方法,传递的参数statement, 传递占位符的参数只能传递一个。而且它的方法名称都是固定。而真实在开发环境下不使用SqlSession封装的方法,而是习惯自己定义方法,自己调用自己的方法。
1.1 实现
(1)创建一个dao接口并定义自己需要的方法。
public interface UserDao {
/**
* 查询所有
* @return
*/
public List<User> findAll();
}
(2)创建映射文件
<?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">
<!--namespace:命名空间
必须和dao相同
-->
<mapper namespace="com.ykq.dao.UserDao">
<select id="findAll" resultType="com.ykq.entity.User">
select * from tb_user
</select>
</mapper>
注意: namespace必须和dao接口一样,而且标签的id必须和你接口的方法名一样。
(3)测试
@Test
public void testFindAll() throws Exception{
Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(resourceAsReader);
SqlSession session=factory.openSession();
//获取相应接口的代理对象
UserDao userDao=session.getMapper(UserDao.class);
List<User> list = userDao.findAll();
System.out.println(list);
session.commit();
session.close();
}
常见bug
namespace和接口名不对应或xml文件没有注册到mybatis配置文件中。
映射文件中的标签id和接口中方法名不对应
2.传递多个参数。
在dao接口中某些方法可能需要传递多个参数,譬如: 登录(username,password
需要在参数处使用@Param()为参数起名。
3.添加时如何返回递增的主键值。
需要返回添加数据库后的id值。
<!--添加用户
useGeneratedKeys:设置使用生成的主键
keyProperty: 赋值给哪个属性
-->
<insert id="addUser" parameterType="com.ykq.entity.User"
useGeneratedKeys="true" keyProperty="userId">
insert into tb_user values(null,#{username},#{realname})
</insert>
4.解决列名和属性名不一致。
问题: 查询时返回一个null,或者某个列没有值
可以有两种解决办法:
第一种: 为查询的列起别名,而别名和属性名一致。
<!--根据id查询学生信息-->
<select id="findOne" resultType="com.ykq.entity.Student">
select stu_id id,stu_name name,stu_age age from tb_stu where stu_id=#{id}
</select>
第二种: 使用resultMap完成列和属性之间的映射关系。
<resultMap id="StuMapper" type="com.ykq.entity.Student">
<!--主键的映射关系 column:列名 property:属性名-->
<id column="stu_id" property="id"/>
<!--普通列的映射关系-->
<result column="stu_name" property="name"/>
<result column="stu_age" property="age"/>
</resultMap>
<!--resultType和ResultMap二者只能用一个-->
<select id="findOne" resultMap="StuMapper">
select * from tb_stu where stu_id=#{id}
</select>
若列名和属性名有些一致的,可以在resultMap中不写映射关系。
5.动态sql
什么是动态sql:
根据参数的值,判断sql的条件。
name!=null address
select * from 表名 where name=#{name} and address=#{address}
name==null
select * from 表名.
mybatis中动态sql标签有哪些?
if标签--单条件判断
//如果name不为null则按照name查询 如果为null则查询所有
public List<Account> findByCondition(@Param("name")String name,@Param("money") Double money);
<select id="findByCondition" resultType="com.ykq.entity.Account">
select * from account where 1=1
<if test="name!=null and name!=''">
and name=#{name}
</if>
<if test="money!=null">
and money=#{money}
</if>
</select>
choose标签 多条件分支判断
<select id="findByCondition02" resultType="com.ykq.entity.Account">
select * from account where 1=1
<choose>
<when test="name!=null and name!=''">
and name=#{name}
</when>
<when test="money!=null">
and money=#{money}
</when>
<otherwise>
and isdeleted=0
</otherwise>
</choose>
</select>
where标签
面的sql都加了 where 1=1 ,如果不使用where 1=1 那么你的动态sql可能会出错。 能不能不加where 1=1? 可以 可以使用where标签,作用:可以自动为你添加where关键字,并且可以帮你去除第一个and \ or。
<select id="findByCondition" resultType="com.ykq.entity.Account">
select * from account
<where>
<if test="name!=null and name!=''">
and name=#{name}
</if>
<if test="money!=null">
and money=#{money}
</if>
</where>
</select>
set标签
配合if标签使用,一般用在修改语句。若传递的参数值为null,那么不修改该列的值。
foreach(循环)标签
循环标签,可以处理一些动态的批量任务,如批量添加、查询、删除等。可以传入一个数组或者一个list集合,然后通过foreach标签将集合内的条件,一个个的放入sql语句,从而实现动态的批量处理效果。
<!--foreach 查询-->
<!-- 若使用的为数组array 为集合 那么就用list
collection:类型
item:数组中每个元素赋值的变量名
open: 以谁开始
close:以谁结束
separator:分割符
-->
<select id="findIds" resultMap="StuMapper">
select <include refid="zz"/> from t_stu where id in
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
sql片段
执行查询语句时不建议使用select *, 建议把查询的列写出。
6.通过dao和映射文件的关联来完成crud
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zsy</groupId>
<artifactId>mybatis08</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!--junit依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<!--log4j依赖-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
创建实体类:
package com.zsy.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author : zhou
* @date : 20:47 2022/6/1
* 使用 lombok自动生成
*/
@Data//get、set和重写toString方法
@NoArgsConstructor//无参构造
@AllArgsConstructor//有参构造
public class Student {
private Integer id;
private String name;
private Integer age;
private String sex;
}
dao:
package com.zsy.dao;
import com.zsy.entity.Student;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author : zhou
* @date : 20:50 2022/6/1
*/
public interface StudentDao {
//查询
public List<Student> findAll();
//条件查询
public Student findBy(@Param("stu_name")String stu_name,@Param("stu_age")Integer stu_age);
//添加
public void add(Student s);
//修改
public void upd(Student s);
//删除
public void del(int id);
}
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">
<!--namespace:命名空间
可以随便起名,但是后期我们要求命名空间的值必须和所对应的dao相同
-->
<mapper namespace="com.zsy.dao.StudentDao">
<resultMap id="ResultMap" type="com.zsy.entity.Student">
<!--主键的映射关系 column:列名 property:属性名-->
<id column="stu_id" property="id"/>
<!--普通的映射关系-->
<result column="stu_name" property="name"/>
<result column="stu_age" property="age"/>
</resultMap>
<!--添加-->
<insert id="add" parameterType="com.zsy.entity.Student">
insert into t_stu values(null,#{name},#{age},#{sex})
</insert>
<!--修改-->
<update id="upd" parameterType="com.zsy.entity.Student">
update t_stu
<set>
<if test="name!=null and name!=''">
stu_name=#{name},
</if>
<if test="age!=null and age!=''">
stu_age=#{age},
</if>
<if test="sex!=null and sex!=''">
sex=#{sex}
</if>
</set>
where stu_id=#{id}
</update>
<!--删除-->
<delete id="del" parameterType="com.zsy.entity.Student">
delete from t_stu where stu_id=#{id}
</delete>
<!--查询所有信息-->
<select id="findAll" resultMap="ResultMap">
select * from t_stu
</select>
<!--条件查询-->
<select id="findBy" resultMap="ResultMap">
select * from t_stu
<where>
<if test="stu_name!=null and stu_name=''">
and stu_name=#{stu_name}
</if>
<if test="stu_age!=null and stu_age=''">
and stu_age=#{stu_age}
</if>
</where>
</select>
</mapper>
测试:
package com.zsy.test;
import com.zsy.dao.StudentDao;
import com.zsy.entity.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.Reader;
import java.util.List;
/**
* @author : zhou
* @date : 20:50 2022/6/1
*/
public class StudentTest {
//查询所有信息
@Test
public void findAll() throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
StudentDao sd = session.getMapper(StudentDao.class);
List<Student> l = sd.findAll();
System.out.println(l);
session.close();
}
//条件查询
@Test
public void findBy() throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
StudentDao sd = session.getMapper(StudentDao.class);
Student s = sd.findBy("张角",40);
System.out.println(s);
session.close();
}
//添加
@Test
public void insert() throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
StudentDao sd = session.getMapper(StudentDao.class);
Student s = new Student();
s.setName("赵云");
s.setAge(25);
s.setSex("男");
sd.add(s);
session.commit();
session.close();
}
//修改
@Test
public void update() throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
StudentDao sd = session.getMapper(StudentDao.class);
Student s = new Student(2,"貂蝉",18,"女");
sd.upd(s);
session.commit();
session.close();
}
//删除
@Test
public void delete() throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
StudentDao sd = session.getMapper(StudentDao.class);
sd.del(5);
session.commit();
session.close();
}
}
7.mybatis映射文件处理特殊字符.
在mapper中写sql语句时,会遇到一些特殊的字符,会与sql代码会产生冲突,如sql中的语句:
小于号,就是一种特殊字符。
解决方法一:转义标签 <
方法二:<![CDATA[sql]]>
<![CDATA[ sql 语句 ]]>标记,将sql语句包裹住,不被解析器解析
9.联表查询
多对一 : 从多的一方来查询一的一方。
根据员工id查询员工信息并携带部门信息。
方法一:
创建实体类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Integer id;
private String name;
private Integer age;
private String job;
private Integer deptId;
private Dept dept;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
private Integer id;
private String name;
}
EmpMapper.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">
<!--namespace:命名空间
命名空间的值必须和所对应的dao相同
-->
<mapper namespace="com.zsy.dao.EmpDao">
<sql id="ed">
e.id,e.name,e.age,e.job,e.dept_id,d.id did,d.name dname
</sql>
<resultMap id="empMap" type="com.zsy.entity.Emp">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
<result column="job" property="job"/>
<result column="dept_id" property="deptId"/>
<!--association: 表示一的一方
property: 它表示属性名
javaType: 该属性名对应的数据类型
-->
<association property="dept" javaType="com.zsy.entity.Dept">
<id column="did" property="id"/>
<result column="dname" property="name"/>
</association>
</resultMap>
<!--联表查询-->
<select id="findId" resultMap="empMap">
select <include refid="ed"/> from tb_emp e join tb_dept d on e.dept_id=d.id where e.id=#{id}
</select>
</mapper>
方法二:
用map封装返回类型 -----不推荐。
public Map findById(Integer id);
<select id="findId" resultType="java.util.Map">
select <include refid="empAndDept"/> from tb_emp e join tb_dept d on e.dept_id = d.id where e.id=#{id}
</select>