Mybatis实现CRUD操作
导入相关依赖
创建实体类User
创建Mybatis主配置文件:SqlMapConfig.xml
创建IUserDao接口。
创建于接口对应的映射配置文件:IUserDao.xml
创建测试类:MybatisTest
查询所有用户操作:findAll
添加用户操作:saveUser
更新用户操作:updateUser
删除用户操作:deleteUser
根据id查询一个用户信息:findById
模糊查询操作:findAllByName
查询用户总记录条数:findTotal
获得插入用户的id: getIdAfterInsert 【重点】
OGNL表达式 【重点】
参数深入(QueryVo类)【重点】
返回值深入(解决实体类与表字段命名不相同时候的返回值封装失败问题)【重点】
导入相关依赖
jar
org.mybatis
mybatis
3.4.5
mysql
mysql-connector-java
5.1.32
log4j
log4j
1.2.17
junit
junit
4.12
创建实体类User
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
//get、set、toString方法省略
}
创建Mybatis主配置文件:SqlMapConfig.xml
导入主配置文件约束
> <?xml version="1.0" encoding="UTF-8"?>
> /p>
> PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
> "http://mybatis.org/dtd/mybatis-3-config.dtd">
配置环境
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
创建IUserDao接口。路径与中配置的路径相同
public interface IUserDao {
}
创建于接口对应的映射配置文件:IUserDao.xml 路径与中配置的路径相同,只是在resources中
导入映射文件约束
> <?xml version="1.0" encoding="UTF-8"?>
> /p>
> PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
创建测试类:MybatisTest
package itlearn.zhi.test;
import itlearn.zhi.dao.IUserDao;
import itlearn.zhi.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.Date;
import java.util.List;
public class MybatisTest {
private InputStream in;
private SqlSession session;
private IUserDao dao;
//定义初始化方法,并设置@Before:在测试方法执行前执行
@Before
public void init() throws IOException {
//1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产SqlSession对象:相当于Connection对象
session = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
dao = session.getMapper(IUserDao.class);
}
//定义事务提交以及资源关闭方法。且设置@After:在测试方法执行后执行
@After
public void destory() throws IOException {
//提交事务:Mybatis默认是需要手动提交事务的
session.commit();
//6.释放资源
session.close();
in.close();
}
}
查询所有用户操作:findAll()
在接口中添加查询所有用户操作的方法
public interface IUserDao {
//查询所有
public List<User> findAll();
}
在接口映射配置文件中配置findAll方法
<mapper namespace="itlearn.zhi.dao.IUserDao">
<select id="findAll" resultType="itlearn.zhi.domain.User">
SELECT * FROM USER;
</select>
</mapper>
在测试类MybatisTest中添加测试方法
@Test
public void testSelect() throws IOException {
List<User> users = dao.findAll();
for (User user : users) {
System.out.println(user);
}
}
添加用户操作:saveUser()
在接口中添加saveUser方法
public interface IUserDao {
//保存用户
public void saveUser(User user);
}
在接口映射配置文件中为saveUser方法添加配置
<mapper namespace="itlearn.zhi.dao.IUserDao">
<insert id="saveUser" parameterType="itlearn.zhi.domain.User">
INSERT INTO user(username,address,sex,birthday) VALUES (#{username},#{address},#{sex},#{birthday});
</insert>
</mapper>
<!--
parameterType="itlearn.zhi.domain.User":指定参数类型为User实体类
VALUES (#{username},#{address},#{sex},#{birthday});:指定参数#{username},格式为#{User类的字段名}
-->
在测试类中添加测试方法
@Test
public void testSave(){
User user = new User();
user.setUsername("光头强");
user.setAddress("小森林");
user.setSex("男");
user.setBirthday(new Date());
dao.saveUser(user);
}
更新用户操作:updateUser
在接口中添加updateUser方法
public void updateUser(User user);
在配置文件中的配置
<update id="updateUser" parameterType="itlearn.zhi.domain.User">
UPDATE user SET username = #{username},address = #{address},sex=#{sex},birthday=#{birthday} WHERE id = #{id} ;
</update>
删除用户操作:deleteUser
在接口中添加deleteUser方法
//根据id删除用户
public void deleteUser(Integer id);//也可以是int类型,建议使用包装类型
在接口映射配置文件中配置deleteUser方法
<delete id="deleteUser" parameterType="Integer">
DELETE FROM user WHERE id = #{uid};
</delete>
<!--
如果参数类型是int/Integer类型,可以写int/Integer/java.lang.Integer都可以
如果只有一个参数,那么where条件中,只需要 #{任意字符}【重点】
-->
根据id查询一个用户信息:findById
在接口中添加findById方法
//根据id查询用户
public User findById(Integer id);
在接口映射配置文件中配置findById方法
<select id="findById" parameterType="Integer" resultType="itlearn.zhi.domain.User">
SELECT * FROM user WHERE id = #{uid};
</select>
模糊查询操作:findAllByName
在接口中添加findAllByName方法
//根据username进行模糊查询
public List<User> findAllByName(String username);
在接口映射配置文件中配置findAllByName方法
<!-- 第一种配置 -->
<select id="findAllByName" parameterType="String" resultType="itlearn.zhi.domain.User">
SELECT * FROM user WHERE username LIKE '%${value}%';
</select>
<!--
在配置模糊查询时候,需要使用 '%${value}%',其中${value}是固定不变的,只能是value,区分大小写。
这种配置方式,在执行的时候实际是执行的: Preparing: SELECT * FROM user WHERE username LIKE '%王%'; 是字符串的拼接---【不推荐使用】
-->
<!-- 第二种配置 -->
<select id="findAllByName" parameterType="String" resultType="itlearn.zhi.domain.User">
SELECT * FROM user WHERE username LIKE #{name};
</select>
<!--
这种配置要在调用方法中使用dao.findAllByName("%王%");
这种配置在执行时:Preparing: SELECT * FROM user WHERE username LIKE ?;
Parameters: %王%(String)
实际上是使用的PrepareStatement预处理---【推荐使用】
-->
添加测试方法
@Test
public void testFindAllByName(){
List<User> users = dao.findAllByName("%王%"); //指定模糊查询
for (User user : users) {
System.out.println(user);
}
}
查询用户总记录条数:findTotal
在接口中添加该方法
//查询记录总条数
public Integer findTotal();
在接口映射配置文件中配置该方法
<select id="findTotal" resultType="Integer">
SELECT COUNT(id) FROM user;
</select>
获得插入用户的id: getIdAfterInsert
在接口中添加该方法
public void getIdAfterInsert(User user);
在接口映射文件中配置该方法
<insert id="getIdAfterInsert" parameterType="itlearn.zhi.domain.User">
<selectKey keyProperty="id" keyColumn="id" resultType="Integer" order="AFTER">
SELECT last_insert_id();
</selectKey>
INSERT INTO user(username,address,sex,birthday) VALUES (#{username},#{address},#{sex},#{birthday});
</insert>
<!--
<selectKey></selectKey>标签中属性:
keyProperty="id" :对应实体类属性名
keyColumn="id" :对应数据库中字段名称
resultType="Integer" : 返回值类型
order="AFTER" : 表示在insert语句执行之后执行此语句。
SELECT last_insert_id(); :查询插入最后一条记录的id值
-->
定义测试方法
@Test
public void testGetId(){
User user = new User();
user.setUsername("邪恶小法师");
user.setAddress("邪恶森林");
user.setSex("男");
user.setBirthday(new Date());
dao.getIdAfterInsert(user);
System.out.println(user.getId()); //打印输出:51
}
OGNL表达式
Object Graphic Navigation Language 对象图导航语言
它是通过对象的取值方法来获取数据,只不过在写法上把get给省略了
比如:我们获取用户的名称:
类中的写法:user.getUsername()
OGNL表达式写法:user.username
那么:Mybatis中为什么直接写username,而不用user. 的方式呢?
因为在ParameterType中已经指定了属性所属的类,所以此时不需要再写对象名。
当有多个参数,且分属不同类时,创建QueryVo对象,封装各个参数,使参数只有QueryVo一个
参数深入(QueryVo类)概念理解
所谓的QueryVo类就是将所有的查询条件进一步封装到一个对象中,这个对象就叫查询条件对象(QueryVo),在传递参数的时候,统一传递此QueryVo对象,然后在指定参数#{}的时候,使用OGNL表达式,即使用"user.username"的形式。其中,user为QueryVo的属性,username为user类的属性。具体看代码实现。
创建QueryVo类,封装参数
package itlearn.zhi.domain;
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
在接口中定义模糊查询方法,参数为QueryVo
public List<User> queryUser(QueryVo vo);
在接口映射配置文件中配置方法
<select id="queryUser" parameterType="itlearn.zhi.domain.QueryVo" resultType="itlearn.zhi.domain.User">
SELECT * FROM user WHERE username LIKE #{user.username};
</select>
<!-- 指定的参数类型为QueryVo类型,在sql语句中使用#{user.username} ,即OGNL表达式-->
测试方法
@Test
public void testQueryUser(){
QueryVo vo = new QueryVo();
User user = new User();
user.setUsername("%王%");
vo.setUser(user);
List<User> users = dao.queryUser(vo);
for (User user1 : users) {
System.out.println(user1);
}
返回值深入(解决实体类与表字段命名不相同时候的返回值封装失败问题)
概念解析
1. 当我们命名的实体类属性值和数据表字段值相同的时候,执行查询,查询到的结果会通过【反射】的方式自动封装成对应的实体类对象。
2. 但是当我们的实体类属性命名和数据表字段值不相同的时候,则查询结果不能通过反射自动封装成对应的实体类对象,这时就需要通过别的方式来帮助查询结果封装到对应的实体类对象中
3. 当实体类属性命名和数据表字段值不相同的时候通常有两种方式来帮助查询结果封装到指定对象中。
一:在查询的时候,给数据表的字段起一个与实体类中属性一样的别名。即在sql语句中使用 as 关键字
二:手动在与dao层接口映射的配置文件中指定实体类属性值与数据表字段的映射关系
两种方法的解析
在查询的时候,给数据表的字段起一个与实体类中属性一样的别名。【效率较高】
<select id="findAll" resultType="itlearn.zhi.domain.User">
select (数据表中的字段值) AS (实体类中与数据表字段值对应的属性值),xxx AS xxx FROM (表名)
</select>
手动在与dao层接口映射的配置文件中指定实体类属性值与数据表字段的映射关系【开发效率较高】
<!-- 配置查询结果的列名和实体类中属性值对应关系 -->
<resultMap id="userMap" type="cn.zhi.domain.User">
<!-- 主键的对应 -->
<id property="userId" column="id"></id>
<!-- 非主键的对应 -->
<result property="实体类属性名" column="数据表字段名"></result>
<result property="实体类属性名" column="数据表字段名"></result>
<result property="实体类属性名" column="数据表字段名"></result>
<result property="实体类属性名" column="数据表字段名"></result>
<result property="实体类属性名" column="数据表字段名"></result>
</resultMap>
<!-- 在配置查询时候,指定映射关系 -->
<select id="" resultMap="userMap">
select * from user
</select>
解析:
1. 所有的配置要写在<resultMap>标签内
2. 个<resultMap>指定一个标识id:<resultMap id="userMap">
3. 给<resultMap>指定返回值封装成的对象类型:type="cn.zhi.domain.User"
4. 主键的配置:<id property="userId" column="id"></id>
property:值为实体类中与数据表中主键对应的属性名
column: 值为数据表中的主键字段值
5. 非主键的对应使用<result>标签
property:值为实体类中与数据表中非主键对应的属性名
column: 值为数据表中的非主键字段名