mybatis里面的#{}和${}
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
parameterType和resultType
parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。
selectOne和selectList
selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:
org.apache.ibatis.exceptions.TooManyResultsException
selectList可以查询一条或多条记录
Dao开发方法
使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper接口开发方法。
原始Dao开发方式
原始Dao开发方式需要编写Dao和Dao的实现类
public interface UserDao {
/**
* 根据user的id查询user信息
* @param id
* @return
*/
public User findUserById(int id);
/**
* 根据用户名模糊查询
* @param username
* @return
*/
public List<User> findUserByUserName(String username);
/**
* 更新用户
* @param user
*/
public User updateUser(Integer id);
}
userDaoImpl类public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
super();
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(int id) {
SqlSession openSession = this.sqlSessionFactory.openSession();
User user = openSession.selectOne("queryUserById",id);
openSession.close();
return user;
}
@Override
public List<User> findUserByUserName(String username) {
SqlSession openSession = this.sqlSessionFactory.openSession();
List<User> list = openSession.selectList("queryUserByUsername", username);
return list;
}
@Override
public void updateUser(String username,Integer id) {
SqlSession openSession = this.sqlSessionFactory.openSession();
openSession.update("updateUserById", id);
openSession.commit();
openSession.close();
}
}
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">
<!-- namespace:命名空间,用于隔离sql -->
<mapper namespace="user">
<!-- 根据用户id查询 -->
<select id="queryUserById"
parameterType="int"
resultType="cn.itcast.mybatis.pojo.User">
SELECT * FROM
user WHERE id=#{id}
</select>
<!-- 根据用户name模糊查询 -->
<select id="queryUserByUsername" parameterType="String" resultType="cn.itcast.mybatis.pojo.User">
SELECT * FROM
user WHERE username LIKE #{username}
</select>
<!-- 新增用户 -->
<insert id="saveUser" parameterType="cn.itcast.mybatis.pojo.User">
<!-- 配置返回自增主键
keyColumn:声明数据库表列的主键
keyProperty:声明pojo那个键为主键
order:在插入前执行还是插入后执行
resultType:主键类型
-->
<selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int">
SELECT
LAST_INSERT_ID()
</selectKey>
INSERT INTO `user`
(username,birthday,sex,address) VALUES
(#{username},#{birthday},#{sex},#{address})
</insert>
<update id="updateUser" parameterType="id">
update from user set username = #{username} where id = #{id}
</update>
</mapper>
userDaoTestpublic class UserDaoTest {
private UserDao userDao;
@Before
public void init() throws Exception{
SqlSessionFactoryBuilder sessionFactoryBuilder = new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sessionFactory = sessionFactoryBuilder.build(inputStream);
this.userDao = new UserDaoImpl(sessionFactory);
}
@Test
public void findByUserIdTest(){
User user = userDao.findUserById(28);
System.out.println(user);
}
@Test
public void findByUserByNameTest(){
List<User> list = userDao.findUserByUserName("测");
for (User user : list) {
System.out.println(user);
}
}
}
问题
原始Dao开发中存在以下问题:
Dao方法体存在重复代码,通过SqlSessionFactory创建的SqlSession,调用SqlSession的数据库操作方法;调用SqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不利于开发维护。
Mapper动态代理方式开发
开发规范
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
1、 Mapper.xml文件中的namespace与mapper接口的类路径相同。
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
Mapper.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必须和类路径一致 -->
<mapper namespace="cn.itcast.mybatis.pojo.UserMapper">
<!-- 根据id查询用户 -->
<!--
Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
-->
<select id="queryUserById" parameterType="java.lang.Integer"
resultType="cn.itcast.mybatis.pojo.User">
SELECT * FROM
user WHERE id=#{id}
</select>
</mapper>
UserMapper接口public interface UserMapper {
/**
* 根据用户id查询
* @param id
* @return
*/
public User queryUserById(int id);
}
测试public class UserMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws Exception{
SqlSessionFactoryBuilder sessionFactoryBuilder = new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
this.sqlSessionFactory = sessionFactoryBuilder.build(inputStream);
}
@Test
public void queryUserByIdTest(){
SqlSession openSession = this.sqlSessionFactory.openSession();
UserMapper userMapper = openSession.getMapper(UserMapper.class);
User user = userMapper.queryUserById(28);
System.out.println(user);
openSession.close();
}
}
SqlMapConfig.xml配置文件
配置内容
注意:SqlMapConfig.xml中配置的内容和顺序如下
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
typeAliases类型别名
别名 | 映射的类型 |
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
map | Map |
自定义别名
在SqlMapConfig.xml中配置
<typeAliases>
<!-- 单个别名定义 -->
<typeAliasalias="user"type="cn.itcast.mybatis.po.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<packagename="cn.itcast.mybatis.po"/>
<packagename="其它包"/>
</typeAliases>
mappers映射器
Mapper配置的几种方法
使用相对于类路径的资源
<mapper resource="sqlmap/User.xml" />
使用mapper接口类路径
<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
<package name=""/>
注册指定包下的所有mapper接口
<package name="cn.itcast.mybatis.mapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中