“基础:Dao开发”的版本间差异
跳到导航
跳到搜索
第238行: | 第238行: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == Mapper动态代理 == | ||
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。<br/> | |||
* (省略了接口实现类,通过反射来实现) | |||
=== 使用规范 === | |||
Mapper接口开发需要遵循以下规范: | |||
# Mapper.xml文件中的'''namespace'''与mapper接口的'''类路径'''相同。 | |||
# Mapper接口'''方法名'''和Mapper.xml中定义的每个'''statement的id'''相同 | |||
# Mapper接口方法的'''输入参数类型'''和mapper.xml中定义的每个sql的'''parameterType'''的类型相同 | |||
# Mapper接口方法的'''输出参数类型'''和mapper.xml中定义的每个sql的'''resultType'''的类型相同 | |||
[[File:Mapper动态代理.png|300px]] | |||
=== User.java === | |||
(同上,略)<br/> | |||
# 路径:“cn.itcast.mybatis.po.User”; | |||
=== UserMapper.xml === | |||
<syntaxhighlight lang="xml" line highlight="5,7,12,17"> | |||
<?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="cn.itcast.mybatis.mapper.UserMapper"> | |||
<!-- 根据id获取用户信息 --> | |||
<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User"> | |||
select * from user where id = #{id} | |||
</select> | |||
<!-- 自定义条件查询用户列表 --> | |||
<select id="findUserByUsername" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User"> | |||
select * from user where username like '%${value}%' | |||
</select> | |||
<!-- 添加用户 --> | |||
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.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> | |||
</mapper> | |||
</syntaxhighlight> | |||
* (需要在SqlMapConfig.xml中添加映射文件) | |||
# namespace 为 UserMapper.java路径(“cn.itcast.mybatis.mapper.UserMapper”); | |||
# UserMapper.xml 与 UserMapper.java 同名不同后缀,且位于同一路径下; | |||
=== UserMapper.java === | |||
<syntaxhighlight lang="java" line highlight="3,5,7"> | |||
Public interface UserMapper { | |||
//根据用户id查询用户信息 | |||
public User findUserById(int id) throws Exception; | |||
//查询用户列表 | |||
public List<User> findUserByUsername(String username) throws Exception; | |||
//添加用户信息 | |||
public void insertUser(User user)throws Exception; | |||
} | |||
</syntaxhighlight> | |||
* 路径:“cn.itcast.mybatis.po.User”; | |||
接口定义有如下特点: | |||
# UserMapper.java 与 UserMapper.xml 同名不同后缀,且位于同一路径下; | |||
# ..方法名 与 ...statement的id相同 | |||
# ..方法的输入参数类型 与 ...statement的parameterType的类型相同 | |||
# ..方法的输出参数类型 与 ...statement的resultType的类型相同 | |||
=== 测试 UserMapperTest.java === | |||
<syntaxhighlight lang="java" line highlight="16,19,21"> | |||
Public class UserMapperTest extends TestCase { | |||
private SqlSessionFactory sqlSessionFactory; | |||
protected void setUp() throws Exception { | |||
//mybatis配置文件 | |||
String resource = "sqlMapConfig.xml"; | |||
InputStream inputStream = Resources.getResourceAsStream(resource); | |||
//使用SqlSessionFactoryBuilder创建sessionFactory | |||
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); | |||
} | |||
Public void testFindUserById() throws Exception { | |||
//获取session | |||
SqlSession session = sqlSessionFactory.openSession(); | |||
//获取mapper接口的代理对象 | |||
UserMapper userMapper = session.getMapper(UserMapper.class); | |||
//调用代理对象方法 | |||
User user = userMapper.findUserById(1); | |||
System.out.println(user); | |||
//关闭session | |||
session.close(); | |||
} | |||
@Test | |||
public void testFindUserByUsername() throws Exception { | |||
SqlSession sqlSession = sqlSessionFactory.openSession(); | |||
UserMapper userMapper = sqlSession.getMapper(UserMapper.class); | |||
List<User> list = userMapper.findUserByUsername("张"); | |||
System.out.println(list.size()); | |||
} | |||
Public void testInsertUser() throws Exception { | |||
//获取session | |||
SqlSession session = sqlSessionFactory.openSession(); | |||
//获取mapper接口的代理对象 | |||
UserMapper userMapper = session.getMapper(UserMapper.class); | |||
//要添加的数据 | |||
User user = new User(); | |||
user.setUsername("张三"); | |||
user.setBirthday(new Date()); | |||
user.setSex("1"); | |||
user.setAddress("北京市"); | |||
//通过mapper接口添加用户 | |||
userMapper.insertUser(user); | |||
//提交 | |||
session.commit(); | |||
//关闭session | |||
session.close(); | |||
} | |||
} | |||
</syntaxhighlight> | |||
# 利用反射来获取接口实现类: | |||
#: '''<syntaxhighlight lang="java">UserMapper userMapper = session.getMapper(UserMapper.class);</syntaxhighlight>''' |
2020年10月10日 (六) 02:13的最新版本
关于
使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper接口开发方法。
原始Dao开发
User.java
public class User {
//属性名和数据库表的字段对应
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex
+ ", birthday=" + birthday + ", address=" + address + "]";
}
}
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">
<mapper namespace="test">
<!-- 在 映射文件中配置很多sql语句 -->
<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
SELECT * FROM USER WHERE id=#{value}
</select>
<!-- 根据用户名称模糊查询用户信息,可能返回多条 -->
<select id="findUserByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User">
SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>
<!-- 添加用户 -->
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address) value(#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 删除 用户 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
<!-- 根据id更新用户 -->
<update id="updateUser" parameterType="cn.itcast.mybatis.po.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}
where id=#{id}
</update>
</mapper>
- 需要在SqlMapConfig.xml中添加映射文件。
UserDao.java
public interface UserDao {
//根据id查询用户信息
public User findUserById(int id) throws Exception;
//根据用户名列查询用户列表
public List<User> findUserByName(String name) throws Exception;
//添加用户信息
public void insertUser(User user) throws Exception;
//删除用户信息
public void deleteUser(int id) throws Exception;
}
UserDaoImpl.java
public class UserDaoImpl implements UserDao {
// 需要向dao实现类中注入SqlSessionFactory
// 这里通过构造方法注入
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
User user = sqlSession.selectOne("test.findUserById", id);
} finally{
session.close();
}
return user;
}
@Override
public List<User> findUserByName(String name) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
List<User> list = sqlSession.selectList("test.findUserByName", name);
} finally{
session.close();
}
return list;
}
@Override
public void insertUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
sqlSession.insert("test.insertUser", user);
} finally{
session.close();
}
}
@Override
public void deleteUser(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
sqlSession.delete("test.deleteUser", id);
sqlSession.commit();
} finally{
session.close();
}
}
}
- 实现UserDao接口方法;
- 注入sqlSessionFactory(构造方法或其他方法注入)到私有属性sqlSessionFactory;
- 方法体中,通过sqlSession(线程不安全,方法体内)实现数据交互;
- (“SqlSession sqlSession = sqlSessionFactory.openSession();”会读取相应配置及映射文件内容;)
- 资源的关闭与释放(最好添加try-catch块???);
测试:UserDaoImplTest.java
public class UserDaoImplTest {
private SqlSessionFactory sqlSessionFactory;
// 此方法是在执行testFindUserById之前执行
@Before
public void setUp() throws Exception {
// 创建sqlSessionFactory
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
}
@Test
public void testFindUserById() throws Exception {
// 创建UserDao的对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
// 调用UserDao的方法
User user = userDao.findUserById(1);
System.out.println(user);
}
}
- 业务代码中应该先获取配置文件流,并由sqlSessionFactoryBuilder(一次性,方法局部变量)生成sqlSessionFactory对象(共用,应用运行期内);
- 用sqlSessionFactory做为参数,创建接口实现类的对象;
- UserDao userDao = new UserDaoImpl(sqlSessionFactory); 多态,向上转型
问题
原始Dao开发中存在以下问题:
- 代码重复:Dao实现类的方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法
SqlSession sqlSession = sqlSessionFactory.openSession(); try { sqlSession.insert("insertUser", user); sqlSession.commit(); } finally{ session.close(); }
- 硬编码:调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得于开发维护。
sqlSession.insert("insertUser", user);
Mapper动态代理
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
- (省略了接口实现类,通过反射来实现)
使用规范
Mapper接口开发需要遵循以下规范:
- Mapper.xml文件中的namespace与mapper接口的类路径相同。
- Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
- Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
- Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
User.java
(同上,略)
- 路径:“cn.itcast.mybatis.po.User”;
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 namespace="cn.itcast.mybatis.mapper.UserMapper">
<!-- 根据id获取用户信息 -->
<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
select * from user where id = #{id}
</select>
<!-- 自定义条件查询用户列表 -->
<select id="findUserByUsername" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User">
select * from user where username like '%${value}%'
</select>
<!-- 添加用户 -->
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.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>
</mapper>
- (需要在SqlMapConfig.xml中添加映射文件)
- namespace 为 UserMapper.java路径(“cn.itcast.mybatis.mapper.UserMapper”);
- UserMapper.xml 与 UserMapper.java 同名不同后缀,且位于同一路径下;
UserMapper.java
Public interface UserMapper {
//根据用户id查询用户信息
public User findUserById(int id) throws Exception;
//查询用户列表
public List<User> findUserByUsername(String username) throws Exception;
//添加用户信息
public void insertUser(User user)throws Exception;
}
- 路径:“cn.itcast.mybatis.po.User”;
接口定义有如下特点:
- UserMapper.java 与 UserMapper.xml 同名不同后缀,且位于同一路径下;
- ..方法名 与 ...statement的id相同
- ..方法的输入参数类型 与 ...statement的parameterType的类型相同
- ..方法的输出参数类型 与 ...statement的resultType的类型相同
测试 UserMapperTest.java
Public class UserMapperTest extends TestCase {
private SqlSessionFactory sqlSessionFactory;
protected void setUp() throws Exception {
//mybatis配置文件
String resource = "sqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//使用SqlSessionFactoryBuilder创建sessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
Public void testFindUserById() throws Exception {
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获取mapper接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//调用代理对象方法
User user = userMapper.findUserById(1);
System.out.println(user);
//关闭session
session.close();
}
@Test
public void testFindUserByUsername() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> list = userMapper.findUserByUsername("张");
System.out.println(list.size());
}
Public void testInsertUser() throws Exception {
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获取mapper接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//要添加的数据
User user = new User();
user.setUsername("张三");
user.setBirthday(new Date());
user.setSex("1");
user.setAddress("北京市");
//通过mapper接口添加用户
userMapper.insertUser(user);
//提交
session.commit();
//关闭session
session.close();
}
}
- 利用反射来获取接口实现类:
UserMapper userMapper = session.getMapper(UserMapper.class);