Mybatis的CRUD
代理对象(dao)的执行过程(跟踪源码图)
//动态代理
public class MapperProxyFactory<T> {
protected T newInstance(MapperProxy<T> mapperProxy){
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface }, mapperProxy) //第一个参数为类加载器,第二个参数为实现接口数组,第三个参数为如何代理,这里重点关注第三个参数(后面肯定是要反射了)
}
}
编写代码实现增删改查功能
- IUserDao接口
//用户的持久层接口
public interface IUserDao {
//查询所有用户
List<User> findAll();
//保存用户
void saveUser(User user);
//更新用户
void updateUser(User user);
//根据Id删除用户
void deleteUser(Integer userId);
//根据id查询用户信息
User findById(Integer userId);
//查询总用户数
int findTotal();
//根据queryVo中的条件查询用户
List<User> findUserByVo(QueryVo vo);
}
- 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="com.itheima.dao.IUserDao">
<!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
<resultMap id="userMap" type="uSeR">
<!-- 主键字段的对应 -->
<id property="userId" column="id"></id>
<!--非主键字段的对应-->
<result property="userName" column="username"></result>
<result property="userAddress" column="address"></result>
<result property="userSex" column="sex"></result>
<result property="userBirthday" column="birthday"></result>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userMap">
<!--select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;-->
select * from user;
</select>
<!-- 保存用户 -->
<insert id="saveUser" parameterType="user">
<!-- 配置插入操作后,获取插入数据的id -->
<selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
</insert>
<!-- 更新用户 -->
<update id="updateUser" parameterType="USER">
update user set username=#{userName},address=#{userAddress},sex=#{userAex},birthday=#{userBirthday} where id=#{userId}
</update>
<!-- 删除用户-->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{uid}
</delete>
<!-- 根据id查询用户 -->
<select id="findById" parameterType="INT" resultMap="userMap">
select * from user where id = #{uid}
</select>
<!-- 根据名称模糊查询 -->
<select id="findByName" parameterType="string" resultMap="userMap">
select * from user where username like #{name}
<!-- select * from user where username like '%${value}%'-->
</select>
<!-- 获取用户的总记录条数 -->
<select id="findTotal" resultType="int">
select count(id) from user;
</select>
<!-- 根据queryVo的条件查询用户 -->
<select id="findUserByVo" parameterType="com.itheima.domain.QueryVo" resultMap="userMap">
select * from user where username like #{user.username}
</select>
</mapper>
OGNL表达式:
- Object Graphic Navigation Language(对象 图 导航 语言)
- 它是通过对象的取值方法来获取数据,在写法上把get给省略了。比如:获取用户名称 类中写法:user.getUsername() OGNL:user.username
- mybatis在parameterType中已经提供了属性所属的类,所以不需要写对象名,可以直接写属性名
Mybatis编写Dao层开发(断点调试,跟踪源码)
编写代码步骤分析
- SqlSessionFactoryBuilder接受SqlMapConfig.xml文件流,构建出SqlSessionFactory对象
- SqlSessionFactory读取SqlMapConfig.xml中连接数据库和mapper映射信息,用来生产出真正操作数据库的SqlSession对象
- SqlSession对象有两大作用:(1)生成接口代理对象 (2)定义通用增删改查方法。 接下来无论使用哪个分支,除了连接数据库信息,还需要得到sql语句
- 作用:第一点是作用(1)第二点作用(2)
- 在SqlSessionImpl对象的getMapper()方法中分两步来实现。第一:先用SqlSessionFactory读取的数据库连接信息创建Connection对象。第二:通过jdk代理模式创建出代理对象作为getMapper()方法返回值,这里主要工作是在创建代理对象时第三个参数处理类里面得到sql语句,执行对应CRUD操作
- 在SqlSessionImpl对象中提供selectList()方法,当然实际mybatis框架中还有selectOne,insert等方法,这些方法内也分两步。第一:用SqlSessionFactory读取的数据库连接信息创建出jdbc的COnnection对象,第二:直接得到sql语句,使用jdk的Connection对象进行对应的CRUD操作
- 封装结果集:无论使用分支一生成代理对象,还是直接使用分支二提供的通用CRUD方法,我们都要对返回的数据库结果集进行封装,编程java对象返回给调用者。所以我们必须要知道调用者所需要的返回类型
总结:通过以上流程不难看出,无论是让mybatis帮我们创建代理对象还是直接使用mybatis提供的CRUD方法,其本质都是JDBC的Connection对象,执行对应的sql语句,最终封装结果集。只是注解和xml配置文件两种开发模式在传递sql语句和返回值类型的方式上有所差异而已。如下图
示例代码
/**
* MyvatisDao层开发,用户接口实现类
* @author eric
* @Company http://www.ithiema.com
*/
public class UserDaoImpl implements IUserDao {
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory){
this.factory = factory;
}
@Override
public List<User> findAll() {
//1.根据factory获取SqlSession对象
SqlSession session = factory.openSession();
//2.调用SqlSession中的方法,实现查询列表
List<User> users = session.selectList("com.itheima.dao.IUserDao.findAll");//参数就是能获取配置信息的key
//3.释放资源
session.close();
return users;
}
@Override
public void saveUser(User user) {
//1.根据factory获取SqlSession对象
SqlSession session = factory.openSession();
//2.调用方法实现保存
session.insert("com.itheima.dao.IUserDao.saveUser",user);
//3.提交事务
session.commit();
//4.释放资源
session.close();
}
@Override
public void updateUser(User user) {
//1.根据factory获取SqlSession对象
SqlSession session = factory.openSession();
//2.调用方法实现更新
session.update("com.itheima.dao.IUserDao.updateUser",user);
//3.提交事务
session.commit();
//4.释放资源
session.close();
}
@Override
public void deleteUser(Integer userId) {
//1.根据factory获取SqlSession对象
SqlSession session = factory.openSession();
//2.调用方法实现更新
session.update("com.itheima.dao.IUserDao.deleteUser",userId);
//3.提交事务
session.commit();
//4.释放资源
session.close();
}
@Override
public User findById(Integer userId) {
//1.根据factory获取SqlSession对象
SqlSession session = factory.openSession();
//2.调用SqlSession中的方法,实现查询一个
User user = session.selectOne("com.itheima.dao.IUserDao.findById",userId);
//3.释放资源
session.close();
return user;
}
@Override
public int findTotal() {
//1.根据factory获取SqlSession对象
SqlSession session = factory.openSession();
//2.调用SqlSession中的方法,实现查询一个
Integer count = session.selectOne("com.itheima.dao.IUserDao.findTotal");
//3.释放资源
session.close();
return count;
}
}
//----------------------------
/**
* 测试mybatis的crud操作
*/
public class MybatisTest {
private InputStream in;
private IUserDao userDao;
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.使用工厂对象,创建dao对象
userDao = new UserDaoImpl(factory);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
//6.释放资源
in.close();
}
/**
* 测试查询所有
*/
@Test
public void testFindAll(){
//5.执行查询所有方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
}
}
Mybatis执行过程(CRUD)
PreparedStatement对象它的执行方法。
excute:它能执行CURD中的任意一种语句,它的返回值是boolean类型,表示是否有结果集,有是true,没有false。
excuteUpdate:它只能执行CUD语句,查询语句无法执行。它的返回值是影响数据库记录的行数
excuteQuery:它只能执行SELECT语句,无法执行增删改,执行结果是封装的结果集ResultSet对象
配置文件(代理dao)
-
配置文件jdbcConfig.properties
<!-- 配置文件名,存在rousource目录下 --> jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/eesy_mybatis jdbc.username=root jdbc.password=1234
-
SqlMapConfig.xml中的配置properties
- 可以在标签内部配置连接数据库的信息。也可以通过属性引用外部配置文件信息
- resource属性: 常用的。用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下。
- url属性:是要求按照Url的写法来写地址。
- URL:Uniform Resource Locator 统一资源定位符。它是可以唯一标识一个资源的位置。
- 它的写法:http://localhost:8080/mybatisserver/demo1Servlet
协议 主机 端口 URI - URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的。
<!-- 示例代码 --> <properties url="file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties"> <!-- <property name="driver" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"></property> <property name="username" value="root"></property> <property name="password" value="1234"></property>--> </properties> <!--配置环境--> <environments default="mysql"> <!-- 配置mysql的环境--> <environment id="mysql"> <!-- 配置事务 --> <transactionManager type="JDBC"></transactionManager> <!--配置连接池--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </dataSource> </environment> </environments>
-
使用typeAliases配置别名
- ypeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就不再区分大小写
<typeAlias type="com.my.domain.User" alias="user"></typeAlias>
- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写
<package name="com.my.domain"></package>
- package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了
<!-- 配置映射文件的位置 --> <mappers> <!--<mapper resource="com/itheima/dao/IUserDao.xml"></mapper>--> <!-- package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了 --> <package name="com.my.dao"></package> </mappers>
- ypeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就不再区分大小写