mybatis是如何将sql执行结果封装为目标对象并返回的?有哪些映射形式
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis是如何将sql执行结果封装为目标对象并返回的?有哪些映射形式相关的知识,希望对你有一定的参考价值。
第一种是使用<resultMap>标签,逐一定义列名和对象属性名之间的映射关系。第二种是使用sql列的别名功能,将列别名书写为对象属性名,
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。 参考技术A 是写一个resultmap然后指明字段和属性映射关系就行 参考技术B username=#1,password=#2 where id=#0这些代码写的有问题,应该是对应的UserInfo里面的属性名,如useName,password,id等。
MyBatis学习
一、MyBatis简介
MyBatis是一个对JDBC进行封装的持久层框架,只需关注SQL本身,而不必去处理(注册驱动、创建connection、创建statement、手动设置参数、结果集检查)的代码。
XML或注解将要执行的statement配置起来,通过Java对象和statement的sql进行映射,生成最终的sql语句,由MyBatis框架执行sql并将结果映射成Java对象返回。
MyBatis和Hibernate的区别:
1、不完全的ORM框架,需要sql语句
2、直接写sql语句,灵活度高,性能好
3、与数据库相关(MySQL、Oracle用不同映射文件)
JDBC存在的问题:
1、创建连接connection、释放资源影响性能(数据库连接池可解决)
2、(sql、参数、结果集)硬编码,代码不易维护
二、MyBatis架构
1、SqlMapConfig.xml是核心配置文件,配置运行环境等信息;Mapper.xml是映射配置文件,配置了操作数据库的sql语句,需要在SqlMapConfig.xml中配置。
2、通过MyBatis环境等配置信息构造会话工厂SqlSessionFactory。
3、由会话工厂SqlSessionFactory创建会话sqlSession,由sqlSession操作数据库。
4、底层通过Executor执行器接口操作数据库,接口有两个实现:基本执行器、缓存执行器
5、Mapped Statement也是一个底层封装对象,包装了MyBatis配置信息和sql映射信息等。映射配置文件Mapper.xml中一个sql对应一个Mapped Statement对象,sql的id即是MappedStatement的id。
6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、POJO、Executor通过Mapped Statement在执行sql前将输入的Java对象映射至sql中,输入参数映射就是JDBC中对prepareStatement设置参数
7、Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、POJO、Executor通过Mapped Statement在执行sql后将输出结果映射到Java对象中,输出结果映射过程相当于JDBC中对结果的解析处理过程。
三、MyBatis入门
1、导包
核心包:MyBatis-3.2.7.jar
依赖包:lib下所有包
数据库驱动包:mysql-connector-java-5.1.17-bin.jar
日志配置文件:log4j.properties
2、在src下创建核心配置文件SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC"-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 和spring整合后 environments配置将废除--> <environments default="development"> <environmentid="development"> <!-- 使用jdbc事务管理--> <transactionManagertype="JDBC"/> <!-- 数据库连接池--> <dataSourcetype="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password "value="root"/> </dataSource> </environment> </environments> </configuration>
3、创建POJO(JavaBean) User,属性表与表中字段对应
Public class User { privateintid; private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 生日 private String address;// 地址 setter&getter }
4、在src下创建映射配置文件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"> </mapper>
namespace用于隔离sql语句
5、加载映射文件User.xml到SqlMapConfig.xml
<mappers> <mapperresource="sqlmap/User.xml"/> </mappers>
四、增删改查用户
1、根据ID查询用户信息
1.1 User.xml中
<!-- 根据id获取用户信息 --> <select id="findUserById" parameterType="Integer" resultType="cn.guojie.mybatis.domain.User"> // MyBatis已为Java.lang.Integer用别名Integer select * from user where id = #{id} </select>
parameterType:入参类型,通过ONGL从输入对象中获取参数值拼接到sql中
resultType:返回结果集类型,将sql查询结果的一行记录数据映射为resultType指定的类型对象
#{id}:设置占位符,并将入参id传给sql
1.2 测试
public class UserTest { //会话工厂,单例,可重复使用 private SqlSessionFactory sqlSessionFactory; @Before // 在测试方法前执行 public void createSqlSessionFactory() throws IOException { // 读取核心配置文件 String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); // 创建SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream); } // 根据 id查询用户信息 @Test public void testFindUserById() { // 数据库会话实例 SqlSession sqlSession = null; try { // 创建数据库会话实例sqlSession sqlSession = sqlSessionFactory.openSession(); // 查询单个记录,根据用户id查询用户信息,查询多条记录用selectList,命名空间+.+sql中的id User user = sqlSession.selectOne("test.findUserById", 10); System.out.println(user); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } } }
2、根据用户名查询用户信息
2.1 User.xml中
<!-- 自定义条件查询用户列表 --> <select id="findUserByUsername" parameterType="java.lang.String" resultType="cn.guojie.mybatis.domain.User"> select * from user where username like \'%${value}%\' // 也可以是"%"#{id}"%" </selec
${}:拼接字符串,基本类型必须用value
2.2 测试
// 根据用户名称模糊查询用户信息 @Test public void testFindUserByUsername() { // 数据库会话实例 SqlSession sqlSession = null; try { // 创建数据库会话实例sqlSession sqlSession = sqlSessionFactory.openSession(); // 模糊查询,查询用户名为张的用户 List<User> list = sqlSession.selectList("test.findUserByUsername", "张"); System.out.println(list.size()); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } }
#{}和${}的区别:
#{}:占位符,防止SQL注入,通常在=后
${}:拼串,只能是value,将参数拼接到sql中。在页面或者action中校验,不可输入SQL关键字和空格来防止SQL注入。通常在like后
3、添加用户
3.1 User.xml中
<!-- 添加用户 --> <inser tid="insertUser" parameterType="cn.guojie.mybatis.domain.User"> insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) </insert>
3.2 测试
// 添加用户信息 @Test public void testInsert() { // 数据库会话实例 SqlSession sqlSession = null; try { // 创建数据库会话实例sqlSession sqlSession = sqlSessionFactory.openSession(); // 添加用户信息 User user = new User(); user.setUsername("张小明"); user.setAddress("河南郑州"); user.setSex("1"); user.setPrice(1999.9f); sqlSession.insert("test.insertUser", user); //提交事务,需要手动提交事务 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } }
4、MySQL自增主键返回
用来查询上一个插入的ID
<insert id="insertUser" parameterType="cn.guojie.mybatis.domain.User"> <!-- selectKey将主键返回,需要再返回 --> <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>
LAST_INSERT_ID():数据库海曙,返回自增的主键
keyProperty: 将返回的主键放入入参id中保存
order:相对于insert语句的执行顺序
resultType:id的类型,也就是keyproperties中属性的类型
5、MySQL中用UUID实现主键
<insert id="insertUser" parameterType="cn.guojie.mybatis.domain.User"> <selectKey resultType="java.lang.String" order="BEFORE" keyProperty="id"> select uuid() </selectKey> insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address}) </insert>
6、删除用户
6.1 User.xml中
<!-- 删除用户 --> <delete id="deleteUserById" parameterType="int"> delete from user where id=#{id} </delete>
6.2 测试
// 根据id删除用户 @Test public void testDelete() { // 数据库会话实例 SqlSession sqlSession = null; try { // 创建数据库会话实例sqlSession sqlSession = sqlSessionFactory.openSession(); // 删除用户 sqlSession.delete("test.deleteUserById",18); // 提交事务 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } }
7、修改用户
7.1 User.xml
<!-- 更新用户 --> <update id="updateUser" parameterType="cn.guojie.mybatis.domain.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} </update>
7.2 测试
@Test public void testUpdate() { // 数据库会话实例 SqlSession sqlSession = null; try { // 创建数据库会话实例sqlSession sqlSession = sqlSessionFactory.openSession(); // 添加用户信息 User user = new User(); user.setId(16); user.setUsername("张小明"); user.setAddress("河南郑州"); user.setSex("1"); user.setPrice(1999.9f); sqlSession.update("test.updateUser", user); // 需要手动提交事务 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } }
SqlSession不是线程安全的,在方法体中创建与销毁
五、DAO开发
1、原始DAO开发(用得少)
需要DAO接口及其实现类
不足:
(1) 方法中代码重复(sqlSessionFactory创建SqlSession,调用SqlSession的数据可操作方法)
(2)硬编码(SqlSession操作方法需要指定statement的id)
2、Mapper动态代理(常用)
只需Mapper接口(相当于DAO接口),MyBatis根据接口定义创建接口的动态代理对象
2.1 开发规范
(1)接口方法名和mapper.xml中id名相同
(2)入参类型和mapper.xml中入参parammeterType相同
(3)返回值类型和mapper.xml的返回类型resultType相同
(4)接口类全路径(包名+类名)和mapper.xml中命名空间相同
2.2 映射文件UserMapper.xml 放在mapper包下
<?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.guojie.mybatis.mapper.UserMapper"> ----> 4 <!-- 根据id获取用户信息 --> <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User"> ----> 1 2 3 select * from user where id = #{id} </select> <!-- 自定义条件查询用户列表 --> <select id="findUserByUsername" parameterType="java.lang.String" resultType="cn.guojie.mybatis.domain.User"> select * from user where username like \'%${value}%\' </select> <!-- 添加用户 --> <inser tid="insertUser"parameter Type="cn.guojie.mybatis.domain.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>
2.3 UserMapper接口 和映射文件放在同一目录
Public interface UserMapper { //根据用户id查询用户信息 public User findUserById(int id) throws Exception; //查询用户列表 public List<User> findUserByUsername(String username) throws Exception; //添加用户信息 publicvoid insertUser(User user)throws Exception; }
2.4 加载UserMapper.xml
<!-- 加载映射文件 --> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers>
2.5 测试
Public class UserMapperTest { private SqlSessionFactory sqlSessionFactory; @Before protectedvoid setUp() throws Exception { // 加载mybatis配置文件 String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); // 创建sessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test 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()); } @Test 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(); } }
六、核心配置文件SqlMapConfig.xml
1、<properties>
在src下定义db.properties,其中不能有空格
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8 jdbc.username=root jdbc.password=root
SqlMapConfig.xml中引用
<properties resource="db.properties"/> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> </properties>
2、<typeAliases> 别名
<typeAliases> <!-- 单个别名定义 --> <typeAliasalias="user"type="cn.itcast.mybatis.po.User"/> <!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) --> // 常用 <packagename="cn.guojie.mybatis.domain"/> <packagename="其它包"/> </typeAliases>
3、<mapper>映射
resource=UserMapper.xml的类路径
class=UserMapper接口的类路径,要求mapper接口和mapper.xml同名且在同一目录中
<package class="接口 " /> 注册包下所有接口(常用),要求mapper接口和mapper.xml同名且在同一目录中
以上是关于mybatis是如何将sql执行结果封装为目标对象并返回的?有哪些映射形式的主要内容,如果未能解决你的问题,请参考以下文章
Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?