MyBatis基础入门
1.MyBatis概述
- MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
- Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatement、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
2.为什么要使用MyBatis(使用JDBC编程有哪些问题)?
数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
- 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
- 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。
3.MyBatis架构
- MyBatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
- mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
- mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
- Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor
4.MyBatis入门
创建Maven工程
修改pom.xml导入MyBatis以及Junit和MySql驱动的jar包
<dependencies>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency> <!--junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- mybatis -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
</dependencies>
classpath目录下创建MyBatis的核心配置文件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>
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="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> <!-- 加载映射文件 -->
<mappers>
<mapper resource="User.xml" />
</mappers> </configuration>
创建测试数据库
创建po类 ---Po类作为mybatis进行sql映射使用,po类通常与数据库表对应
package pojo; import java.util.Date; public class User { private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址 getter and setter方法...... @Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
+ address + "]";
} }
创建sql映射文件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">
<!-- namespace:命名空间,做sql隔离 -->
<mapper namespace="test"> <!--
id:sql语句唯一标识
parameterType:指定传入参数类型
resultType:返回结果集类型
#{}占位符:起到占位作用,如果传入的是基本类型(string,long,double,int,boolean,float等),那么#{}中的变量名称可以随意写.
-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="cn.itheima.pojo.User">
select * from user where id=#{id}
</select> <!--
如果返回结果为集合,可以调用selectList方法,这个方法返回的结果就是一个集合,所以映射文件中应该配置成集合泛型的类型
${}拼接符:字符串原样拼接,如果传入的参数是基本类型(string,long,double,int,boolean,float等),那么${}中的变量名称必须是value
注意:拼接符有sql注入的风险,所以慎重使用
-->
<select id="findUserByUserName" parameterType="java.lang.String" resultType="cn.itheima.pojo.User">
select * from user where username like '%${value}%'
</select> <!--
#{}:如果传入的是pojo类型,那么#{}中的变量名称必须是pojo中对应的属性.属性.属性.....
如果要返回数据库自增主键:可以使用select LAST_INSERT_ID()
-->
<insert id="insertUser" parameterType="cn.itheima.pojo.User" >
<!-- 执行 select LAST_INSERT_ID()数据库函数,返回自增的主键
keyProperty:将返回的主键放入传入参数的Id中保存.
order:当前函数相对于insert语句的执行顺序,在insert前执行是before,在insert后执行是AFTER
resultType:id的类型,也就是keyproperties中属性的类型
-->
<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> <delete id="delUserById" parameterType="int">
delete from user where id=#{id}
</delete> <update id="updateUserById" parameterType="cn.itheima.pojo.User">
update user set username=#{username} where id=#{id}
</update>
</mapper>
加载映射文件 --mybatis框架需要加载映射文件,将User.xml添加在SqlMapConfig.xml
<!-- 加载映射文件 -->
<mappers>
<mapper resource="User.xml" />
</mappers>
创建测试类UserTest进行测试
查询单个User对象
@Test
public void test1() throws IOException {
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
// 通过会话执行sql 第一个参数是名称空间+SqlID 第二个参数表示sql执行需要的参数
User user = openSession.selectOne("test.findUserById", 1);
System.out.println(user.toString());
// 关闭会话
openSession.close(); }
通过username进行模糊查询
@Test
public void test2() throws IOException {
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
// 调用User.xml中的魔化查询方法 返回集合
List<User> selectList = openSession.selectList("test.findUserByName", "张");
// 循环结果
System.out.println(selectList.size());
for (User user : selectList) {
System.out.println(user.toString());
}
// 关闭会话
openSession.close();
}
添加一条User用户到数据库
@Test
public void test3() throws IOException {
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
// 创建需要插入的User对象
User user = new User();
user.setUsername("Jimisun");
user.setSex("1");
user.setAddress("北京");
System.out.println("====插入前的User的id=" + user.getId());
// 会话调用插入的sql
openSession.insert("test.insertUser", user);
// 默认mybatis自动开启事务,需要手动提交事务
openSession.commit();
System.out.println("====插入后的User的id=" + user.getId());
// 关闭会话
openSession.close();
}
删除一条记录
@Test
public void test4() throws IOException {
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
// 会话执行sql操作
openSession.delete("test.deleteUserById", 1);
// 提交事务
openSession.commit();
// 关闭会话
openSession.close();
}
更新一条记录
@Test
public void test5() throws Exception {
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
//创建User对象
User user = new User ();
user.setId(1);
user.setUsername("王麻子");
openSession.update("test.updateByUserId", user);
//提交事务
openSession.commit();
//关闭会话
openSession.close(); }
5.使用MyBatis的开发方法
- 原生Dao方法
- UserDao 接口
- UserDaoImpl 实现类
- findUserById() -----方法内使用MyBatis框架进行操作
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
// 通过会话执行sql 第一个参数是名称空间+SqlID 第二个参数表示sql执行需要的参数
User user = openSession.selectOne("test.findUserById", 1);
System.out.println(user.toString());
// 关闭会话
openSession.close();
- findUserById() -----方法内使用MyBatis框架进行操作
- Mapper接口开发 ----Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
- 开发规范
Mapper.xml文件中的namespace与mapper接口的类路径相同。
- Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
- 开发目录
- UserDao 接口 遵循上面规则
- UserServiceImpl直接调用
@Test
public void testFindUserById() throws Exception{
SqlSession openSession = factory.openSession();
//通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class); User user = mapper.findUserById(1);
System.out.println(user);
}
- 开发规范
6.SqlMapConfig.xml配置文件
- properties(属性) 常用于加载配置文件
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理-->
<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> typeAliases(类型别名)
<typeAliases>
<!-- 定义单个pojo类别名
type:类的全路劲名称
alias:别名
-->
<typeAlias type="cn.itheima.pojo.User" alias="user"/> <!-- 使用包扫描的方式批量定义别名
定以后别名等于类名,不区分大小写,但是建议按照java命名规则来,首字母小写,以后每个单词的首字母大写
-->
<package name="cn.itheima.pojo"/>
</typeAliases>mappers(映射器)
- 相对于类路径的资源
<mapper resource="sqlmap/User.xml" />
- 使用mapper接口开发
<mapper class="cn.redrat.mybatis.mapper.UserMapper"/>
- 注册指定包下所有的mapper接口
<package name="cn.redrat.mybatis.mapper"/>
- 注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
- 相对于类路径的资源
7.输入映射和输出映射
- Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。
parameterType(输入类型)
- 传递基本类型包含String
- 传递pojo对象
- 传递vo对象
resultType(输出类型)
- 返回pojo类型
- 返回集合
- 返回基本类型包含String
8.动态Sql --通过mybatis提供的各种标签方法实现动态拼接sql
- if
<!-- 传递pojo综合查询用户信息 注意要做不等于空字符串校验-->
<select id="findUserList" parameterType="user" resultType="user">
select * from user
where 1=1
<if test="id!=null">
and id=#{id}
</if>
<if test="username!=null and username!=''">
and username like '%${username}%'
</if>
</select> - where
<select id="findUserList" parameterType="user" resultType="user">
select * from user
<where>
<if test="id!=null and id!=''">
and id=#{id}
</if>
<if test="username!=null and username!=''">
and username like '%${username}%'
</if>
</where>
</selectwhere标签的作用可以去掉sql语句中的where 1=1 并自动处理第一个 and
- foreach
<select id="findUserByIds" parameterType="cn.redrat.pojo.QueryVo" resultType="cn.redrat.pojo.User">
select * from user
<where>
<if test="ids != null">
<!--
foreach:循环传入的集合参数
collection:传入的集合的变量名称
item:每次循环将循环出的数据放入这个变量中
open:循环开始拼接的字符串
close:循环结束拼接的字符串
separator:循环中拼接的分隔符
-->
<foreach collection="ids" item="id" open="id in (" close=")" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
9.MyBatis关联查询核心示例
- 一对一查询
<!-- 一对一:自动映射 -->
<select id="findOrdersAndUser1" resultType="cn.redrat.pojo.CustomOrders">
select a.*, b.id uid, username, birthday, sex, address
from orders a, user b
where a.user_id = b.id
</select> <!-- 一对一:手动映射 -->
<!--
id:resultMap的唯一标识
type:将查询出的数据放入这个指定的对象中
注意:手动映射需要指定数据库中表的字段名与java中pojo类的属性名称的对应关系
-->
<resultMap type="cn.redrat.pojo.Orders" id="orderAndUserResultMap">
<!-- id标签指定主键字段对应关系
column:列,数据库中的字段名称
property:属性,java中pojo中的属性名称
-->
<id column="id" property="id"/> <!-- result:标签指定非主键字段的对应关系 -->
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/> <!-- 这个标签指定单个对象的对应关系
property:指定将数据放入Orders中的user属性中
javaType:user属性的类型
-->
<association property="user" javaType="cn.redrat.pojo.User">
<id column="uid" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findOrdersAndUser2" resultMap="orderAndUserResultMap">
select a.*, b.id uid, username, birthday, sex, address
from orders a, user b
where a.user_id = b.id
</select> - 一对多
<resultMap type="cn.redrat.pojo.User" id="userAndOrdersResultMap">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/> <!-- 指定对应的集合对象关系映射
property:将数据放入User对象中的ordersList属性中
ofType:指定ordersList属性的泛型类型
-->
<collection property="ordersList" ofType="cn.redrat.pojo.Orders">
<id column="oid" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
</collection>
</resultMap>
<select id="findUserAndOrders" resultMap="userAndOrdersResultMap">
select a.*, b.id oid ,user_id, number, createtime
from user a, orders b where a.id = b.user_id
</select>
MyBatis基础入门的更多相关文章
- MyBatis基础入门《二十》动态SQL(foreach)
MyBatis基础入门<二十>动态SQL(foreach) 1. 迭代一个集合,通常用于in条件 2. 属性 > item > index > collection : ...
- MyBatis基础入门《十九》动态SQL(set,trim)
MyBatis基础入门<十九>动态SQL(set,trim) 描述: 1. 问题 : 更新用户表数据时,若某个参数为null时,会导致更新错误 2. 分析: 正确结果: 若某个参数为nul ...
- MyBatis基础入门《十八》动态SQL(if-where)
MyBatis基础入门<十八>动态SQL(if-where) 描述: 代码是在<MyBatis基础入门<十七>动态SQL>基础上进行改造的,不再贴所有代码,仅贴改动 ...
- MyBatis基础入门《十七》动态SQL
MyBatis基础入门<十七>动态SQL 描述: >> 完成多条件查询等逻辑实现 >> 用于实现动态SQL的元素主要有: > if > trim > ...
- MyBatis基础入门《十六》缓存
MyBatis基础入门<十六>缓存 >> 一级缓存 >> 二级缓存 >> MyBatis的全局cache配置 >> 在Mapper XML文 ...
- MyBatis基础入门《十五》ResultMap子元素(collection)
MyBatis基础入门<十五>ResultMap子元素(collection) 描述: 见<MyBatis基础入门<十四>ResultMap子元素(association ...
- MyBatis基础入门《十四》ResultMap子元素(association )
MyBatis基础入门<十四>ResultMap子元素(association ) 1. id: >> 一般对应数据库中改行的主键ID,设置此项可以提高Mybatis的性能 2 ...
- MyBatis基础入门《十三》批量新增数据
MyBatis基础入门<十三>批量新增数据 批量新增数据方式1:(数据小于一万) xml文件 接口: 测试方法: 测试结果: =============================== ...
- MyBatis基础入门《十二》删除数据 - @Param参数
MyBatis基础入门<十二>删除数据 - @Param参数 描述: 删除数据,这里使用了@Param这个注解,其实在代码中,不使用这个注解也可以的.只是为了学习这个@Param注解,为此 ...
- MyBatis基础入门《十 一》修改数据
MyBatis基础入门<十 一>修改数据 实体类: 接口类: xml文件: 测试类: 测试结果: 数据库: 如有问题,欢迎纠正!!! 如有转载,请标明源处:https://www.cnbl ...
随机推荐
- Python 实现小数和百分数的相互转换
# -*- coding: utf-8 -*- #百分比转换位小数 # -*- coding: utf-8 -*- s = '20%' # 默认要转换的百分比是字符串aa = float(s.stri ...
- c语言打印一个整数的二进制形式
printf函数没有这个功能,如果想打印一个数的二进制形式,就得自己计算.下面是我看到的最简便的算法: #include <stdio.h> int main(int argc, char ...
- atitit.软件开发概念--过滤和投影 数据操作
atitit.软件开发概念--过滤和投影 数据操作 投影的本质及扩展 物体在太阳光的照射下形成的影子(简称日影)就是平行投影.日影的方向可以反映时间 投影还比喻此物通过彼物表现出来的迹象. 作者::老 ...
- nginx源代码分析--GDB调试
利用gdb[i]调试nginx[ii]和利用gdb调试其他程序没有两样,只是nginx能够是daemon程序,也能够以多进程执行,因此利用gdb调试和寻常会有些许不一样. 当然,我们能够选择将ngin ...
- location [=|$|最长原则|^~](nginx-1.4.4)
优先级由上到下依次递减: location =/a/1.png { return 400; } } location ~* \.png$ { return 403; } location /a/1.p ...
- Nokia Imaging SDK 的高级使用—实时滤镜拍照
有关 Nokia Imaging SDK 的初级使用,可以参考:Nokia Imaging SDK滤镜使用入门 本文的主题: 1.如何 PhotoCaptureDevice 类使用,以及如何在 Med ...
- jmap 查看内存使用直方图
jps -- 查看进程号 jmap -histo pid 查看堆内存中的对象数目.大小统计直方图, 如果带上live则表示先进行一次fullgc 再统计内存使用情况,如下: jmap -hist ...
- 第八课:不一样的链表 linux链表设计哲学 5星级教程
这一课最后实现的链表,和普通链表不同,借鉴了linux内核链表的思想,这也是企业使用的链表. 基础介绍: 顺序表的思考 顺序表的最大问题是插入和删除需要移动大量的元素!如何解决?A:在线性表数据元素之 ...
- python学习笔记(7)--爬虫隐藏代理
说明: 1. 好像是这个网站的代理http://www.xicidaili.com/ 2. 第2,3行的模块不用导入,之前的忘删了.. 3. http://www.whatismyip.com.tw/ ...
- Unix网络编程中的五种I/O模型_转
转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描 ...