目录
在数据库创建admin管理员表为例
一、单元测试
程序员一般会使用的测试方法,是以方法为单位进行测试,这里需要使用junit组件实现。
在pom.xml文件中加入以下代码。
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>provided</scope>
</dependency>
这样我们就可以在方法外加上@Test注解标签直接对该方法实现运行测试,如图
二、增删改查
1.向数据库增添数据
@Test
public void insert(){
Admin admin = new Admin();//数据封装到对象中
admin.setAccount("aaa");
admin.setPassword("132");
admin.setGender("男");
SqlSession sqlSession = MyBatisUtil.getSqlSession();
AdminDao adminDao = sqlSession.getMapper(AdminDao.class);
adminDao.insertAdmin(admin);//拿主键
System.out.println(admin.getId());
sqlSession.commit();//提交数据库事务,程序无异常才提交事务,执行sql。新增修改删除完成后都需手动提交事务
//void insertAdmin(Admin admin);接口中的方法
sqlSession.close();
/*数据库事物:是数据库的一种管理机制,对一次连接数据库过程进行管理
例如:
sql1
其它代码(有异常)
sql2
提交事务(一次执行完所有sql,但是因为在其它代码部分有异常,会终止提交事务,因此sql都不会执行)*/
}
映射文件相应标签
<!--useGeneratedKeys="返回自增主键"
keyProperty="接收主键属性"
keyColumn="主键列"
-->
<insert id="insertAdmin" parameterType="Admin" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
insert into admin(account,password,gender)values (#{account},#{password},#{gender})
</insert>
2.删除数据库数据
删除id为4的管理员信息
@Test
public void delete(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
AdminDao adminDao = sqlSession.getMapper(AdminDao.class);
adminDao.deleteAdmin(4);
sqlSession.commit();
sqlSession.close();
}//void deleteAdmin(int id);接口中的方法
映射文件相应标签
<delete id="deleteAdmin" parameterType="int">delete from admin where id = #{id}</delete>
3.修改数据库数据
修改id为3的管理员信息
@Test
public void update(){
Admin admin = new Admin();
admin.setId(3);
admin.setAccount("ccc");
admin.setPassword("123");
SqlSession sqlSession = MyBatisUtil.getSqlSession();
AdminDao adminDao = sqlSession.getMapper(AdminDao.class);
adminDao.updateAdmin(admin);
sqlSession.commit();
sqlSession.close();
}//void updateAdmin(Admin admin);接口中的方法
映射文件相应标签
<update id="updateAdmin" parameterType="Admin">update admin set account = #{account},password=#{password} where id = #{id}</update>
4.查询返回简单基本类型
单表查询,返回的结果mybatis自动将结果映射到java对象中,但必须要表中列名与类中属性名一致!
注:MySQL中对于两个单词采用A_B链接,但是java使用驼峰表示findAdmin,因此这里我们可以在mybatis.xml配置文件中<settings>标签中加入如下代码即可相互转换,还不影响单表查询因为属性名与列名不一致引起的查询失效。
<setting name="mapUnderscoreToCamelCase" value="true"/>
@Test
public void find1(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
AdminDao adminDao = sqlSession.getMapper(AdminDao.class);
int count = adminDao.findAdminCount();
int id = adminDao.findAdminId("account");
sqlSession.commit();
sqlSession.close();
}//int findAdminCount();接口中的方法
映射文件相应标签
<!--单表查询,返回的结果mybatis自动将结果映射到java对象中,但必须要表中列名与类中属性名一致-->
<!--java.lang.Integer,全类名,这里我们用别名integer代替-->
<select id="findAdminCount" resultType="integer">
select count(*) from admin
</select>
5.返回多个数据
@Test
public void find2(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
AdminDao adminDao = sqlSession.getMapper(AdminDao.class);
List<Admin> admins = adminDao.findAdmins("password");
sqlSession.commit();
sqlSession.close();
}//List<Admin> findAdmins(@Param("orderColumn") String orderColumn);接口方法
映射文件相应标签
<select id="findAdmins" resultType="Admin" parameterType="string">
select ${orderColumn} from admin order by ${orderColumn} desc
</select>
三、关联查询
1.多表查询
(1)准备工作
我们在数据库中再创建两张表student和major
在IDEA分别写出相应的类、接口、映射文件,记得在mybatis.xml配置文件中注册映射文件,如果忘记了具体操作请移步至我的上一篇博客:java后端框架——Mybatis框架搭建
这里有一点值得我们注意的是,以往我们向通过student学生类查询major专业信息,需要在student类中重新定义专业中的属性,如:mid、mname会发生冗余。但是mybatis在封装时想到,我们只需在student类中定义一个major属性即可。将专业信息封装到学生类中,因为mid、mname本质上在major中已经定义过。这样就在学生中关联了专业。
(2)多表查询
<association>标签
因此多表查询,为了使major类的信息存储到student类中我们定义的major属性中去,就需要借助<resultMap>标签。整体结构如下:
//定义 resutlMap
<resultMap id="adminResultMap" type="Admin">
<id column="id" property="id"/>
<result property="account" column="account" />
<result property="password" column="password" />
</resultMap>
注: (1). resutlMap 的 id 属性是 resutlMap 的唯一标识,本例中定义为 “adminResultMap”(2). resutlMap 的 type 属性是映射的 POJO 类型(即该类的类型)(3). id 标签映射主键,result 标签映射非主键(4). property 设置对象属性名称,column 映射查询结果的列名称(这里因为我在IDEA中创建类的属性时名字与数据库列名保持一致故而前后相同,大家根据自己创建类的属性名而定)
//使用 resultMap
<select id="findAdminInfoResultMap" resultMap="adminResultMap">
SELECT id ,account,password FROM admin
</select>
注: (1). 本例的输出映射使用的是 resultMap,而非 resultType(2). resultMap 引用了 adminResultMap(这与上面<resultMap>中的id保持一致)
接下来我通过查询学生及其相关专业为例,演示如何映射关联数据。接口中的方法和测试程序我就不再过多赘述,参考上文即可,这里只演示映射文件内容。
<!--对关联查询到的学生信息进行自定义映射封装-->
<resultMap id="studentMap" type="Student">
<id column="id" property="id"></id>
<result column="num" property="num"></result>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<!--映射关联数据专业名称 先创建一个Major对象,将专业名称封装到Major对象中,再将major对象封装到Student对象中-->
<association property="major" javaType="Major">
<result column="mname" property="name"></result>
</association>
</resultMap>
<select id="findStudentById" resultMap="studentMap">
select
s.id,
s.num,
s.name,
s.gender,
m.name mname
from student s inner join major m on s.majorid = m.id where s.id = #{id}
</select>
注: <association>标签映射关联对象数据。该标签头中俩标签内容:
<property>标签中是要映射关联的类的对象
<javaType>标签放关联对象的类型
* 如果多个查询的属性一致,只是查询结果个数不同,如去掉where条件语句,我们可以让两个select查询共同映射同一个Map,即resultMap映射地址一致。
<connection>标签
当我们想通过专业查询该专业有多少学生时,可以将多个学生封装到一个集合中,这时就要用到<connection>标签,将查询关联到的多条结果封装到集合中去。
<resultMap id="majorMap" type="Major">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<collection property="students" javaType="list" ofType="Student">
<result column="num" property="num"></result>
<result column="sname" property="name"></result>
</collection>
</resultMap>
<select id="findMajorById" resultMap="majorMap" parameterType="int">
select
m.id,
m.name,
s.num,
s.name sname
from major m inner join student s on s.majorid = m.id where m.id = #{id}
</select>
其中,collection 和 association 都需要配置 select 和 column 属性,两者配置方法
相同,参考上文。对应关系如下:
测试代码 :
@Test
public void test1(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
MajorDao majorDao = sqlSession.getMapper(MajorDao.class);
Major major = majorDao.findMajorById(1);
System.out.println(major.getName());
for (Student student:major.getStudents()){
System.out.println(student.getName()+":"+student.getNum());
}
sqlSession.close();
}//Major findMajorById(int id);接口中方法
2.嵌套查询
场景一:将原本的关联查询分成两步或多步,形成嵌套查询,这样虽然简化了sql语句,但是要进行两次或多次sql查询执行,效率劣势。
这里同样不赘述接口方法和测试部分,若无法独立编写,请参考文章开头部分。
<!--嵌套查询,先查主表student学生表,再查关联的major专业表-->
<resultMap id="studentMap1" type="Student">
<id column="id" property="id"></id>
<result column="num" property="num"></result>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<!--封装关联表数据-->
<association property="major" javaType="Major" select="findMajorById" column="majorid">
</association>
</resultMap>
<select id="findStudentById1" resultMap="studentMap1">
select
*
from student s where s.id = #{id}
</select>
<!--嵌套查询学生关联的专业-->
<select id="findMajorById" resultType="Major">
select name from major where id = #{majorid}
</select>
<association>新属性解释:
(1). select:指定关联查询对象的 Mapper Statement ID 为 findDeptByID(即等于子查询中的id)(2). column="majorid":关联查询时将 majorid 列的值传入 findDeptByID,并将 findDeptByID 查询的结果映射到 Emp 的 dept 属性中(即student表的majorid通过此处传给major子表中的id,从而查出专业名称)对应关系如下图:
场景二:当我们通过专业表查询相关专业学生时,因为一对多关系,会导致例如:专业只有四个,但学生有五个而使查询结果个数不一致。在实际开发中,如果要对专业查询表进行分页处理,就会因此导致无法分页。
<!--分页处理,两次查询-->
<resultMap id="majorMap1" type="Major">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<collection property="students" javaType="list" ofType="Student" select="findStudents" column="id">
</collection>
</resultMap>
<!--分两次查询,程序会先执行专业表查询,然后才会通过专业id查出学生,
这样就会固定查出四条数据的结果,分页操作会根据major表的结果执行,而不受关联表查询结果影响-->
<select id="findMajor1" resultMap="majorMap1">
select id,name from major
</select>
<select id="findStudents" resultType="Student">
select num,name from student where majorid = #{id}
</select>
测试和接口部分代码如下:
@Test
public void test3(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
MajorDao majorDao = sqlSession.getMapper(MajorDao.class);
List<Major> major = majorDao.findMajor1();
sqlSession.close();
}//List<Major> findMajor1();接口中方法
四、动态sql
MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。 如果你有使用JDBC 或其他相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空格或在列表的最后省略逗号。动态 SQL 可以彻底处理这种痛苦。
以教师表为例
1.if元素
if 标签可以对传入的条件进行判断
<select id="teachers" resultType="com.mybatispro.model.Teacher">
select * from teacher
<if test="num!=null">
num = #{num}
</if>
<if test="name!=null">
and name = #{name}
</if>
</select>
2.where元素
对于查询条件个数不确定的情况,可使用<where>元素。<where>元素会进行判断,如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以 AND 或 OR 开头,它会剔除掉 AND 或 OR。
用法就是给上面仨<if>标签外套一个<where>标签即可
3.trim元素
where 标签其实用 trim 也可以表示。当 where 后紧随 AND 或则 OR 的 时候,就去除 AND 或者 OR。prefix:前缀,prefixOverrides:覆盖首部指定内容。
<select id="teachers" resultType="com.mybatispro.model.Teacher">
select * from teacher
<trim prefix="where" prefixOverrides="and|or">
<if test="num!=null">
num = #{num}
</if><!--如果num为空,会消除name前的and保证sql语句正确-->
<if test="name!=null">
and name = #{name}
</if>
</trim>
</select>
4.choose元素
配合<when><otherwise>标签使用。when otherwise 相当于if else,可以没有otherwise不能没有when
<select id="teachers" resultType="com.mybatispro.model.Teacher">
select * from teacher
<trim prefix="where" prefixOverrides="and|or">
<choose><!--如果名字不为空,查该老师信息,否则查王老师信息-->
<when test="name!=null">
and name = #{name}
</when>
<otherwise>
and name = '王老师'
</otherwise>
</choose>
</trim>
</select>
5.set元素
Set 元素可以把最后一个逗号去掉,用于更改操作,保证sql语句正确性
<update id="updateTeacher" parameterType="Teacher">
update teacher
<set>
<if test="num!=null">
num = #{num},
</if>
<if test="name!=null">
name = #{name},
</if>
</set>
where id = #{id}
</update>
6.foreach 元素
相当于一个增强for循环。
collection 属性根据传入的参数选择list/array
item 表示集合中每一个元素进行迭代时的别名
open 表示该语句以什么开始separator 表示在每次进行迭代之间以什么符号作为分隔符close 表示以什么结束
@Test
public void test3(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
TeacherDao teacherDao = sqlSession.getMapper(TeacherDao.class);
teacherDao.deleteTeacher(new Integer[]{1,2,3});
sqlSession.commit();
sqlSession.close();
}//void deleteTeacher(Integer[] array);接口中方法
<delete id="deleteTeacher" ><!--删除id在(1,2,3)中的老师-->
delete from teacher where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete><!--完整sql为:delete from teacher where id in(1,2,3) -->
以上是关于mybatis的基本知识,希望能给各位带来收获!如有不正,恳请及时指出。