大家好呀,我是书架。
【Mybatis】快速搭建01介绍了MyBatis框架如何在Dao层接口、映射文件(写SQL语句的Mapper.xml文件)、配置文件SqlMapConfig.xml组合下完成了对数据库的查询操作。
本次内容依然是在快速搭建01开发基础上更加全面的通过示例介绍基本的增删改查操作。
查询操作-select
我们在查询数据库时,通常会传入参数以筛寻符合条件的数据。那么SQL语句是如何接收传入的参数呢?
示例1-传入基本数据类型作为参数
Dao层接口UserMapper增加findById方法
public User findById(int id);
映射文件UserMapper.xml中增加与Dao层接口匹配的如下内容
<!--1.根据传入的参数类型为基本数据类型-->
<select id="findById" parameterType="int" resultType="com.zssj.domain.User">
select * from user where id = #{id}
</select>
示例2-传入引用数据类型作为参数
Dao层接口UserMapper增加findByIdTest方法
public User findByIdTest(User user);
映射文件UserMapper.xml中增加与Dao层接口匹配的如下内容
<!--2.传入的参数类型为引用数据类型-->
<select id="findByIdTest" parameterType="com.zssj.domain.User" resultType="com.zssj.domain.User">
select * from user where id = #{id}
</select>
通过示例1和示例2发现Dao层接口中方法的参数类型和UserMapper.xml中select标签parameterType参数的类型一致,它们是一一对应的。
两个示例语句中的select标签传入参数类型不一样,一个是基本数据类型int,一个是引用数据类型User。
因此select * from user where id = #{id}中的id值,示例一来自于Dao层直接传入的参数,示例二来自user对象中的id值。
而两个示例的查询结果都以resultType="com.zssj.domain.User"形式进行封装。
插入操作-insert
示例3-User对象进行插入
Dao层接口UserMapper增加insert方法
int insert(User user);
映射文件UserMapper.xml中增加与Dao层接口匹配的如下内容
<insert id="insert" >
insert into user(id, username,password) values(#{id}, #{username}, #{password})
</insert>
测试类中的测试代码
@Test
public void test2() throws IOException {
//1. 读取核心配置文件SqlMapConfig.xml
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3. 使用工厂生产一个SqlSession对象
SqlSession session = factory.openSession();
//4. 使用SqlSession创建Dao接口的代理对象
User user = new User();
user.setId(7);
user.setUsername("guanyu");
user.setPassword("hello123");
UserMapper userMapper = session.getMapper(UserMapper.class);
userMapper.insert(user);
//新增数据需要提交事务
session.commit();
//6. 释放资源
session.close();
in.close();
}
在测试方法中,我们手动生成了一个User对象,并且调用Dao接口中的insert方法,完成数据的插入。
目光聚集到Dao接口中的insert方法,发现它的返回值类型是int类型,这代表插入数据库的总条数,我们此次只插入了一条数据,因此返回值是1。
UserMapper.xml中的insert标签里将数据库的所有字段都列出来,并且用#{属性值}的方式进行一一对应,属性值来自Dao层接口传入的User对象的属性值。
上述示例代码展示了运用Mybatis插入简单的数据,可以发现在测试方法中主键id是我们手动赋值,但是在实际生产中,主键id值会被设置为自动增长,不需要自己赋值。
那么在我们插入数据后,如果还想得到数据库中为这条记录生成的id值该怎么办呢?
Mybatis框架也为我们提供了方法。
示例4-MySQL数据库完成id值回显
Dao层接口UserMapper增加insert2方法
int insert2(User user);
映射文件UserMapper.xml中增加与Dao层接口匹配的如下内容
<insert id="insert2" useGeneratedKeys="true" keyProperty="id">
insert into user(id, username,password) values(#{id}, #{username}, #{password})
</insert>
测试类中的方法
@Test
public void test5() throws IOException {
//1. 读取核心配置文件SqlMapConfig.xml
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3. 使用工厂生产一个SqlSession对象
SqlSession session = factory.openSession();
//4. 使用SqlSession创建Dao接口的代理对象
User user = new User();
user.setUsername("liubei");
user.setPassword("hello123");
UserMapper userMapper = session.getMapper(UserMapper.class);
userMapper.insert2(user);
System.out.println(user.getId());
//新增数据需要提交事务
session.commit();
//6. 释放资源
session.close();
in.close();
}
在测试方法中创建实体对象user时,我们并没有主动给id赋值,在实行插入语句insert2后,测试user.getId()方法,获取到了这条记录的id值。
而实现这一功能,主要是在UserMapper.xml中中相应的select标签中,加入了两个参数,第一个是useGeneratedKeys="true" ,第二个是keyProperty="id"。
这两个参数的意思是Mybatis会将数据库获得的id自增值赋值给实体对象的id。
但是这个方法只适用如MySql、SqlServer这样支持主键自增的数据库。而像Oracle数据库不提供主键自增功能,而是使用序列得到一个值,然后将这个值赋值给id,再将数据插入数据库。
对于这种情况,可以通过<selectKey>标签来获取主键的值代码示例如下。
示例5-Oracle数据库完成id回显
Dao层接口UserMapper增加insert3方法
int insert3(User user);
映射文件UserMapper.xml中增加与Dao层接口匹配的如下内容
<insert id="insert3" >
<selectKey keyColumn="id" resultType="int" keyProperty="id" order="BEFORE">
select seq_id.nextval from dual
</selectKey>
insert into user(id, username,password) values(#{id}, #{username}, #{password})
</insert>
我们发现Dao层接口的方法不变,变的是在UserMapper.xml中insert标签中加入了子标签<selectKey>。
Oracle会将从序列seq_id中得到的值通过keyColumn赋值给数据库的id字段,并且通过keyProperty回显给实体对象的id。
更新操作-update
Dao层接口UserMapper增加updateById方法
int updateById(User user);
映射文件UserMapper.xml中增加与Dao层接口匹配的如下内容
<!--修改操作-->
<update id="updateById" parameterType="com.zssj.domain.User">
update user set username = #{username}, password = #{password} where id = #{id}
</update>
测试类中的方法
@Test
public void test3() throws IOException {
//1. 读取核心配置文件SqlMapConfig.xml
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3. 使用工厂生产一个SqlSession对象
SqlSession session = factory.openSession();
//4. 使用SqlSession创建Dao接口的代理对象
User user = new User();
user.setId(6);
user.setUsername("zhugeliang");
user.setPassword("hello123");
UserMapper userMapper = session.getMapper(UserMapper.class);
userMapper.updateById(user);
//新增数据需要提交事务
session.commit();
//6. 释放资源
session.close();
in.close();
}
在测试方法中我们生成了user对象其id为6,因此传入到UserMapper.xml中的updateById方法就会根据此id修改该记录。
删除操作-delete
Dao层接口UserMapper增加deleteById方法
int deleteById(int id);
映射文件UserMapper.xml中增加与Dao层接口匹配的如下内容
<!--删除操作-->
<delete id="deleteById" parameterType="int">
delete from user where id = #{id}
</delete>
测试类中的方法
@Test
public void test5() throws IOException {
//1. 读取核心配置文件SqlMapConfig.xml
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3. 使用工厂生产一个SqlSession对象
SqlSession session = factory.openSession();
//4. 使用SqlSession创建Dao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
userMapper.deleteById(1);
//需要提交事务
session.commit();
//6. 释放资源
session.close();
in.close();
}
多参数参与SQL语句
不知道大家有没有发现在上述的示例中,Dao层接口的参数要么是基本数据类型要么是实体对象,但是参数只有一个,那如果我要传入多个参数怎么办呢?
通过一个例子来说明一下,要求查出id为1,username为zhangsan的密码信息。
Dao层接口UserMapper增加findByParam方法
public User findByParam( int id, String username);
映射文件UserMapper.xml中增加与Dao层接口匹配的如下内容
<select id="findByParam" resultType="com.zssj.domain.User">
select * from user where id = #{id} and username = #{username}
</select>
测试类中的方法
@Test
public void test6() throws IOException {
//1. 读取核心配置文件SqlMapConfig.xml
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3. 使用工厂生产一个SqlSession对象
SqlSession session = factory.openSession();
//4. 使用SqlSession创建Dao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.findByParam(1, "zhangsan");
System.out.println(user);
//新增数据需要提交事务
session.commit();
//6. 释放资源
session.close();
in.close();
}
在Dao层接口方法findByParam中,其参数为两个。运行上述测试代码会发现报错
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database.
Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found.
Available parameters are [arg1, arg0, param1, param2]
报错显示id值没找到,说明Dao层把值传给UserMapper.xml的对应的select标签时出现问题,这时候需要借用注解@param来绑定参数。
因此将Dao层中的方法改为
public User findByParam( @Param("id") int id, @Param("username") String username);
注解@Param("id") 的意思是把此id值绑定给占位符#{id},@Param("username")是把username绑定给占位符#{username}。
这样在多参数传入时就能实现一一对应,再次调用测试方法测试通过。