MyBatis入门主要讲解了Mybatis的基本配置。在这些配置里面需要注意一下问题:
-
持久层接口和持久层接口的映射配置文件必须在相同的包下。
-
持久层接口配置文件中的mapper标签的namespace属性取值必须是持久层就看的全限定类名。
-
SQL语句的配置标签中的id属性值必须和持久层接口的方法名相同。例如上面的<select>标签中的id属性值findAll和UserDao接口中的方法名findAll相同。
接着MyBatis入门继续深入了解,在UserDao接口里面加入根据Id查询用户的方法
package com.liang.dao;
import com.liang.domain.User;
import java.util.List;
public interface UserDao{
/**
* 查询所有用户
* @return
*/
List<User> findAll();
/**
* 根据id查询用户
* @param id
* @return
*/
User findById(int id);
}
同时需要在接口映射文件里面添加相应的SQL语句:根据Id查询用户
<?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.liang.dao.UserDao">
<select id="findAll" resultType="com.liang.domain.User" >
select *from user;
</select>
<!--根据id查询用户-->
<select id="findById" resultType="com.liang.domain.User" parameterType="int">
select *from user where id= #{userID};
</select>
</mapper>
select标签中需要掌握的是其属性。
属性名 | 属性值 |
---|---|
resultType | 用于指定结果集的类型 |
parameterType | 用于指定传入参数的类型 |
**SQL语句中使用的#{}字符:**代表占位符,相当于使用jdbc的prepareStatement时候SQL语句传入的?,都是用于执行语句时候替换为实际的数据。
由于在MyBatis入门中通过main方法进行的测试的,这给后面的测试会带来很多不便,因此我做了在下面做了修改,使用了测试类进行测试,修改代码如下,并且加上了通过id查询用户的方法。
import com.liang.dao.UserDao;
import com.liang.domain.User;
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.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class TestMyBatis {
private SqlSession sqlSession = null;
private InputStream inputStream = null;
private UserDao userDao = null;
@Before
public void init() throws IOException {
inputStream = Resources.getResourceAsStream("SqlConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
sqlSession = sqlSessionFactory.openSession();
userDao = sqlSession.getMapper(UserDao.class);
}
@After
public void destroy() throws IOException {
sqlSession.close();
inputStream.close();
}
/**
* 查询所有用户信息
*/
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for (User user : users)
{
System.out.println(user.toString());
}
}
/**
* 通过ID查询用户
*/
@Test
public void testFindById(){
User user = userDao.findById(41);
System.out.println(user.toString());
}
}
实现保存用户信息
继续在持久层接口UserDao.java中添加保存方法。
/**
* 保存用户
* @param user
*/
void saveUser(User user);
相应的在其对应的接口映射文件中添加SQL语句。
<!--注意此处传入的参数类型是我们自定义的参数类型
相应的#{}占位符写入的内容,也应该是自定义类型的属性名。
此处使用的都是apache提供的一种表达式语言 OGNL
全称:Object Graphic Navigation Language(对象图导航语言)
-->
<insert id="saveUser" parameterType="com.liang.domain.User">
insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex}, #{address});
</insert>
在测试类中添加测试方法。
@Test
public void testSaveUser()
{
User user = new User();
user.setUsername("娃哈啊");
user.setSex("女");
user.setBirthday(new Date());
user.setAddress("陕西");
userDao.saveUser(user);
System.out.println("保存完毕");
}
执行测试方法后,发现数据库里面并没有添加成功,这里和jdbc是相同的,在执行增删改的时候要控制事务的提交,在Mybatis中通过SqlSession对象的commit()方法来提交事务。可以将提交事务的方法加入到 userDao.saveUser(user);后面,也可以加入到 @After里面。
//在测试方法执行完成之后执行
@After
public void destroy() throws IOException {
sqlSession.commit();
sqlSession.close();
inputStream.close();
}
当添加提交方法后,在userDao.saveUser(user);后面打印用户信息发现此时id值为0,其实此处的id值是数据库自增长实现的,因此需要在新增用户后将自动增长的值进行获取。修改接口映射文件如下:
<insert id="saveUser" parameterType="com.liang.domain.User">
<!--配置保存时,获取插入的id
keyColumn: 数据库表对应的字段
keyProperty: User对象的属性
order: 执行顺序
-->
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex}, #{address});
</insert>
修改后在userDao.saveUser(user);后面打印用户信息发现id是我们需要的id.
添加更新用户和以上步骤没有任何区别。
在持久层添加更新方法:
/**
* 更新用户
* @param user
*/
void updateUser(User user);
在持久层对应的映射文件添加SQL语句:
<!--更新用户-->
<update id="updateUser" parameterType="com.liang.domain.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
在测试类中添加测试方法:
/**
* 更新用户
*/
@Test
public void testUpdateUser()
{
User user = userDao.findById(70);
user.setUsername("wahaha");
userDao.updateUser(user);
System.out.println(user);
}
添加删除用户也是相同的三步。
在持久层添加删除方法:
/**
* 通过用户ID删除用户
* @param userId
*/
void deleteUser(int userId);
在相应的配置文件添加SQL语句:
<!--通过用户id删除用户-->
<delete id="deleteUser">
delete from user where id= #{uid}
</delete>
在测试类中添加测试方法:
/**
* 通过用户ID删除用户
*/
@Test
public void testDeleteUser()
{
userDao.deleteUser(70);
System.out.println("删除成功");
}
两种模糊查询的方式
两种方式和上面的一样,都需要三步完成。
方式一
在持久层接口中添加模糊查询的方法
/**
* 根据名称模糊查询
* @param name
* @return
*/
List<User>findByName(String name);
在映射文件中添加SQL语句
<!--根据名称模糊查询-->
<select id="findByName" parameterType="String" resultType="com.liang.domain.User">
select *from user where username like #{username}
</select>
添加测试方法
/**
* 根据名称模糊查询用户
*/
@Test
public void testFindByName()
{
List<User> users = userDao.findByName("%小%");
for (User user : users)
{
System.out.println(user);
}
}
方式二
在持久层接口中添加模糊查询的方法,这一步不做任何改变。
在映射文件中添加SQL语句
<!--根据名称模糊查询
需要注意问题:
1.将#{}占位符改为${value}
2.${value是固定写法,不能该写成其他}-->
<select id="findByName" parameterType="String" resultType="com.liang.domain.User">
select *from user where username like '%${value}%'
</select>
添加测试方法
/**
* 根据名称模糊查询用户
*/
@Test
public void testFindByName()
{
List<User> users = userDao.findByName("小");
for (User user : users)
{
System.out.println(user);
}
}
以上两种方式虽然执行结果相同,但是是有区别的,区别主要体现在执行SQL语句时。
#{}表示一个占位符,相当于PreparedStatement,可以有效的防止SQL注入问题。而且#{}可以接收简单类型的值和 POJO 属性值。
表
示
拼
接
S
Q
L
,
内
容
拼
接
不
能
有
效
防
止
S
Q
L
注
入
,
{}表示拼接SQL,内容拼接不能有效防止SQL注入,
表示拼接SQL,内容拼接不能有效防止SQL注入,{}也可以接收简单类型值和 POJO 属性值。如果parameterType传递耽搁简单型参数${}括号中只能是value。
聚合函数的使用
在持久层接口中添加查询总记录条数的方法
/**
* 查询总记录条数
* @return
*/
int findTotal();
在映射文件中添加SQL语句
<!--查询总记录条数-->
<select id="findTotal" resultType="int">
select count(*) from user
</select>
添加测试方法
/**
* 查询总记录条数
*/
@Test
public void testFindTotal()
{
int res = userDao.findTotal();
System.out.println(res);
}