不使用动态代理的方式
数据库的增删改查操作通常都是在dao层完成,类似的dao接口类如下:
public interface UserDao {
User findUserById(Integer id);
List<User> findUserByName(String username);
}
然后就会有对应的实现类
public class UserDaoImpl implements UserDao {
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
}
@Override
public User findUserById(Integer id) {
// SqlSession是线程不安全的,所以它的最佳使用范围在方法体内
SqlSession session = factory.openSession();
User user = session.selectOne("test.findUserById", id);
return user;
}
@Override
public List<User> findUserByName(String username) {
SqlSession session = factory.openSession();
List<User> list = session.selectList("test.findUserByName", username);
return list;
}
}
对应的sql操作的映射文件User.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:命名空间,可任意起名,代码中会通过该名称空间来调用具体的sql语句 -->
<mapper namespace="test">
<select id="findUserById" parameterType="java.lang.Integer" resultType="blog.csdn.net.mchenys.poj.User">
select * from user where id = #{id}
</select>
<select id="findUserByName" parameterType="java.lang.String" resultType="blog.csdn.net.mchenys.poj.User">
select * from user where username like '%${value}%'
</select>
</mapper>
测试类代码:
public class UserDaoTest {
private SqlSessionFactory factory;
@Before
public void setUp() throws Exception {
InputStream config = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(config);
}
@Test
public void testFindUserById() throws Exception {
UserDao dao = new UserDaoImpl(factory);
User user = dao.findUserById(1);
System.out.println(user);
}
@Test
public void testFindUserByName() throws Exception {
UserDao dao = new UserDaoImpl(factory);
List<User> list = dao.findUserByName("王");
System.out.println(list);
}
}
可以看到,dao层的实现类是需要我们自己去实现的,这部分工作如何让mybatis帮我们完成呢?
其实mybatis是可以实现的,我们只需要定义dao层的接口类,然后mybatis就可以通过动态代理的方式来自动生成对应的实现类。
使用动态代理的方式
使用这种方式是有一定的要求的
映射文件和接口文件的要求
- 接口的名称和映射文件的名称除扩展名外要完全相同
- 接口和映射文件要放在同一个目录下
例如,本例我会在工程下创建一个mapper的包,单独将接口文件和映射文件放在一起。
映射文件中mapper标签的要求
- 映射文件中namespace要等于接口的全路径名称
- 映射文件中sql语句的id要等于接口的方法名称
- 映射文件中传入参数类型要等于接口方法的传入参数类型
- 映射文件中返回结果集类型要等于接口方法的返回值类型,如果接口方法的返回值类型是集合,那么它表示的就是集合中的泛型参数类型
例如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接口代理实现规则:
1.映射文件中namespace要等于接口的全路径名称
2. 映射文件中sql语句的id要等于接口的方法名称
3. 映射文件中传入参数类型要等于接口方法的传入参数类型
4. 映射文件中返回结果集类型要等于接口方法的返回值类型,如果接口方法的返回值类型是集合,那么它表示的就是集合中的泛型参数类型
-->
<mapper namespace="blog.csdn.net.mchenys.mapper.UserMapper">
<!-- 单个查询 -->
<select id="findUserById" parameterType="java.lang.Integer" resultType="blog.csdn.net.mchenys.poj.User">
select * from user where id = #{id}
</select>
<!-- 多个查询 -->
<select id="findUserByName" parameterType="java.lang.String" resultType="blog.csdn.net.mchenys.poj.User">
select * from user where username like '%${value}%'
</select>
<!-- 添加 -->
<insert id="insertUser" parameterType="blog.csdn.net.mchenys.poj.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select last_insert_id()
</selectKey>
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 修改 -->
<update id="updateNameById" parameterType="blog.csdn.net.mchenys.poj.User">
<!-- 由于parameterType的类型是User对象,那么占位符#{}内的属性名必须对应User对象的属性 -->
update user set username = #{username} where id = #{id}
</update>
<!-- 删除 -->
<delete id="deleteById" parameterType="java.lang.Integer">
delete from user where id = #{id}
</delete>
<!-- 返回结果集类型是基本数据类型的例子 -->
<select id="findUserCount" resultType="java.lang.Integer">
select count(*) from user
</select>
</mapper>
对应的UserMapper的接口类就应这样定义
package blog.csdn.net.mchenys.mapper;
import java.util.List;
import blog.csdn.net.mchenys.poj.User;
public interface UserMapper {
//单个查询
public User findUserById(Integer id);
/**
* 动态代理形式用,如果返回结果集为List,那么mybatis会在生成实现类的时候自动调用selectList方法
* @param username
* @return
*/
public List<User> findUserByName(String username);
//添加
public void insertUser(User user) ;
//更新
public void updateNameById(User user);
//删除
public void deleteById(Integer id);
// 查询总数
public Integer findUserCount();
}
ok,完成上面操作后,记得修改SqlMapConfig.xml配置文件,在<mappers>
标签内添加UserMapper.xml映射文件
<!-- 配置映射文件 -->
<mappers>
<mapper resource="User.xml"/>
<!-- 方式1:引入映射文件
<mapper resource="blog/csdn/net/mchenys/mapper/UserMapper.xml"/>
-->
<!-- 方式2:用class属性引入接口类的全路径
规则:
1.接口的名称和映射文件的名称除扩展名外要完全相同
2.接口和映射文件要放在同一个目录下
<mapper class="blog.csdn.net.mchenys.mapper.UserMapper"/>
-->
<!-- 方式3:使用包扫描的方式批量引入Mapper接口 ,规则和方式2一样,建议采用这种-->
<package name="blog.csdn.net.mchenys.mapper"/>
</mappers>
完整SqlMapConfig.xml配置文件可以看上一篇文章,这里就不贴了。
对应的测试类代码:
package blog.csdn.net.mchenys.test;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
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.Before;
import org.junit.Test;
import blog.csdn.net.mchenys.mapper.UserMapper;
import blog.csdn.net.mchenys.poj.User;
public class UserMapperTest {
private SqlSessionFactory factory;
@Before
public void setUp() throws Exception {
InputStream config = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(config);
}
@Test
public void testFindUserById() throws Exception {
SqlSession session = factory.openSession();
// 传入接口class,返回接口的实现类(原理是动态代理的方式生成)
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.findUserById(1);
System.out.println(user);
}
@Test
public void testFindUserByName() throws Exception {
SqlSession session = factory.openSession();
// 传入接口class,返回接口的实现类(原理是动态代理的方式生成)
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> user = mapper.findUserByName("王");
System.out.println(user);
}
@Test
public void testInsertUser() throws Exception {
SqlSession session = factory.openSession();
// 传入接口class,返回接口的实现类(原理是动态代理的方式生成)
UserMapper mapper = session.getMapper(UserMapper.class);
User user = new User();
user.setUsername("小明2");
user.setAddress("深圳");
mapper.insertUser(user);
// 提交事务
session.commit();
}
@Test
public void testUpdateNameById() throws Exception {
SqlSession session = factory.openSession();
// 传入接口class,返回接口的实现类(原理是动态代理的方式生成)
UserMapper mapper = session.getMapper(UserMapper.class);
User user = new User();
user.setUsername("王小明");
user.setId(1);
mapper.updateNameById(user);
// 提交事务
session.commit();
}
@Test
public void testDeleteById() throws Exception {
SqlSession session = factory.openSession();
// 传入接口class,返回接口的实现类(原理是动态代理的方式生成)
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.deleteById(1);
// 提交事务
session.commit();
}
//查询总数
@Test
public void testFindUserCount() throws Exception{
SqlSession session = factory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
Integer count = mapper.findUserCount();
System.out.println(count);
}
}
完整的项目工程结构如下:
其中,红色框起来的就是使用代理方式演示的。