mybatis
简介
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
入门
1、建立 Maven 工程
选择 quickstart,快速建立项目工程
选择 目录,设定工程名称与工程整体架构(域名倒置)
确实引入的 Maven setting 文件与各项配置项准确即可 finish;
工程初步完成之后的整体架构如下图:
2、引入资源 jar 包与创建数据表
导入 mybatis 与mysql 驱动
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
创建 mysql 数据表:
create table user(
user_id int(6) zerofill auto_increment primary key,
user_name varchar(10) not null,
user_gender char(1) not null,
user_province varchar(50) not null,
user_balance decimal(10,2) not null default 2000
);
insert into user(user_id,user_name,user_gender,user_province) values
(15,'遥遥','男','北京市'),
(27,'威威','男','江苏省'),
(46,'楠楠','女','江苏省'),
(6,'洋洋','男','安徽省');
3、编写主体工程代码
首先给大家看下最终的工程整体架构图:
3.1、实体类:UserInfo.java
package cn.yangqunmanman.entity;
/**
* 有参/无参构造方法
* get / set 方法
* tostring 方法
*/
public class UserInfo {
private Integer user_id;
private String user_name;
private String user_gender;
private String user_province;
private Double user_balance;
public UserInfo() {
}
public UserInfo(Integer user_id, String user_name, String user_gender, String user_province, Double user_balance) {
this.user_id = user_id;
this.user_name = user_name;
this.user_gender = user_gender;
this.user_province = user_province;
this.user_balance = user_balance;
}
public Integer getUser_id() {
return user_id;
}
public void setUser_id(Integer user_id) {
this.user_id = user_id;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getUser_gender() {
return user_gender;
}
public void setUser_gender(String user_gender) {
this.user_gender = user_gender;
}
public String getUser_province() {
return user_province;
}
public void setUser_province(String user_province) {
this.user_province = user_province;
}
public Double getUser_balance() {
return user_balance;
}
public void setUser_balance(Double user_balance) {
this.user_balance = user_balance;
}
@Override
public String toString() {
return "UserInfo{" +
"user_id=" + user_id +
", user_name='" + user_name + '\'' +
", user_gender='" + user_gender + '\'' +
", user_province='" + user_province + '\'' +
", user_balance=" + user_balance +
'}';
}
}
3.2、接口:UserMapper.class
package cn.yangqunmanman.mapper;
import cn.yangqunmanman.entity.UserInfo;
import java.util.List;
public interface UserMapper {
// 查询数据 列表返回
List<UserInfo> findAll(UserInfo userInfo);
// 增删改一律整数返回
//多条件删除
int remove(int[] ids);
// 修改
int update(UserInfo userInfo);
// 增加用户
int add(List<UserInfo> list);
}
3.3、UserMapper.xml:xml映射的具体操作流程
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace + id 关联唯一对应的方法 -->
<mapper namespace="cn.yangqunmanman.mapper.UserMapper">
<select id="findAll" parameterType="UserInfo" resultType="UserInfo">
select * from user
<where>
<choose>
<when test="null != user_id">
and user_id=#{user_id}
</when>
<otherwise>
<if test="null != user_name">
and user_name=#{user_name}
</if>
<if test="null != user_gender">
and user_gender=#{user_gender}
</if>
<if test="null != user_province">
and user_province=#{user_province}
</if>
<if test="null != user_balance">
and #{user_balance}>=user_balance
</if>
</otherwise>
</choose>
</where>
</select>
<delete id="remove">
delete from user where user_id in
<foreach collection="array" item="id" open="(" close=")" separator="," >
#{id}
</foreach>
</delete>
<update id="update" parameterType="UserInfo">
update user
<set>
<if test="null != user_id">
user_id=#{user_id},
</if>
<if test="null != user_name">
user_name=#{user_name},
</if>
<if test="null != user_gender">
user_gender=#{user_gender},
</if>
<if test="null != user_province">
user_province=#{user_province},
</if>
<if test="null != user_balance">
user_balance=#{user_balance},
</if>
</set>
where user_id=#{user_id}
</update>
<insert id="add">
insert into user(user_id, user_name,user_gender, user_province, user_balance) values
<foreach collection="list" item="user" separator=",">
(#{user.user_id},#{user.user_name},#{user.user_gender},#{user.user_province},#{user.user_balance})
</foreach>
</insert>
</mapper>
3.4、datasource.properties:java连接mysql的各项参数
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://192.168.150.150:3306/test?useSSL=false
mysql.username=root
mysql.password=12345678
3.5、mybatis.xml:mybatis 的各项配置
<?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>
<properties resource="datasource.properties"/>
<typeAliases>
<package name="cn.yangqunmanman.entity"/>
</typeAliases>
<!-- 默认使用的环境 ID-->
<environments default="mysql">
<!-- 每个 environment 元素定义的环境 ID-->
<!-- 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID。-->
<environment id="mysql">
<!-- 事务管理器的配置-->
<transactionManager type="JDBC"/>
<!-- 数据源的配置-->
<dataSource type="POOLED">
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- class="cn/kgc/mapper/UserMapper" -->
<!-- <mapper resource="cn/kgc/mapper/userMapper.xml"/>-->
<package name="cn.yangqunmanman.mapper"/>
</mappers>
</configuration>
3.6、App:启动工程
package cn.yangqunmanman;
import cn.yangqunmanman.entity.UserInfo;
import cn.yangqunmanman.mapper.UserMapper;
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 java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class App
{
public static void main( String[] args ) throws IOException {
System.out.println( "Hello World!" );
// 固定套路
final String RESOURCE = "mybatis.xml";
InputStream stream = Resources.getResourceAsStream(RESOURCE);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(stream);
SqlSession sqlSession = factory.openSession(true);
UserMapper stuMapper = sqlSession.getMapper(UserMapper.class);
System.out.println("****************************UserInfo 数据查询结果如下**************************");
UserInfo stuInfo = new UserInfo();
stuInfo.setUser_gender("女");
List<UserInfo> stuInfo_list = stuMapper.findAll(stuInfo);
for (UserInfo student : stuInfo_list) {
System.out.println(student);
}
System.out.println("*****************************UserInfo 数据增加结果如下*************************");
ArrayList<UserInfo> list = new ArrayList<>();
UserInfo stuAddInfo1 = new UserInfo(54,"山山","男","江西省",5000.00);
UserInfo stuAddInfo2 = new UserInfo(55,"泽泽","女","福建省",6000.00);
list.add(stuAddInfo1);
list.add(stuAddInfo2);
int addDate = stuMapper.add(list);
System.out.println(addDate);
System.out.println("*****************************UserInfo 数据删除结果如下*************************");
int[] arr = {54,55};
int i = stuMapper.remove(arr);
System.out.println(i);
System.out.println("*****************************UserInfo 数据修改结果如下*************************");
UserInfo stuUpDataInfo = new UserInfo();
stuUpDataInfo.setUser_id(27);
stuUpDataInfo.setUser_gender("女");
int update = stuMapper.update(stuUpDataInfo);
System.out.println(update);
sqlSession.close();
}
}
运行结果依次如下图:
工程 xml 配置—mybatis.xml
- configuration(配置)
- properties(属性)
- typeAliases(类型别名)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
- mappers(映射器)
1、properties(属性)
属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。本文为在 properties 中配置:
<properties resource="datasource.properties"/>
这样在 properties 中设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:
<dataSource type="POOLED">
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
上面的例子中的 username 和 password 将会由 properties 元素中设置的相应值来替换。 driver 和 url 属性将会由 datasource.properties 文件中对应的值来替换。这样就为配置提供了诸多灵活选择。
2、typeAliases(类型别名)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写,可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,在项目中如下配置:
<typeAliases>
<package name="cn.yangqunmanman.entity"/>
</typeAliases>
3、environments(环境配置)
environments 元素定义了如何配置环境。
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
注意:
- 默认使用的环境 ID (default=“development”)
- 每个 environment 元素定义的 环境 ID (id=“development”)
- 事务管理器的配置(type=“JDBC”)
- 数据源的配置(type=“POOLED”)
默认环境和环境 ID 顾名思义。环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID
3.1、事务管理器
在 MyBatis 中有两种类型的事务管理器(也就是 type="[ JDBC|MANAGED]"):
- JDBC 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得连接来管理事务的作用域;
- MANAGED 这个配置几乎什么也不做,从不submit 或 rollback 一个连接,而是让容器来管理事务的整个生命周期,故本文在这不做说明
注意:
如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。后面会做一个spring mvc + mybatis 的项目,到时会详细讲解
3.2、数据源
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
有三种內建的数据源类型(type = “[ UNPOOLED | POOLED | JNDI ]”)
- UNPOOLED 这个数据源的实现没次请求时会打开和关闭连接,故加载会有延迟、速度慢等"不舒服的点",故不多做介绍
- POOLED 这个数据源的实现利用了**“池"的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必须的初始化和认证时间。这样的处理方式现在很"流行”**,能是并发Web应用快速响应请求;
- 这个数据源实现是为了能在如 EJB(Enterprise Java Beans:基于分布式事务处理的企业级应用程序的组件) 或应用服务器这类容器中使用,故不多做介绍
POOLED 配置如下表:
属性 | 说明 | ||
---|---|---|---|
driver | JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类) | ||
url | 数据库的 JDBC URL 地址 | ||
username | 登录数据库的用户名 | ||
password | 登录数据库的密码 | ||
****** | 正常练手项目的连接池配置上面就够了(如本文代码所示) | ||
defaultTransactionIsolationLevel | 默认的连接事务隔离级别 | ||
defaultNetworkTimeout | 等待数据库操作完成的默认网络超时时间(单位:毫秒) | ||
poolMaximumActiveConnections | 在任意时间可存在的活动(正在使用)连接数量,默认值:10 | ||
poolMaximumIdleConnections | 任意时间可能存在的空闲连接数 | ||
poolTimeToWait | 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒) | ||
poolPingQuery | 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。 | ||
poolPingEnabled | 是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。 | ||
poolPingConnectionsNotUsedFor | 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用) | ||
4、mapper(映射器)
到这,MyBatis的行为在上面元素的基本配置结束了,而现在就是来定义 SQL 映射的语句了。所以我们需要告诉 MyBatis 去那找到这些语句,示例如下:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="cn/yangqunmanman/mapper/userMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="cn.yangqunmanman.mapper.UserMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="cn.yangqunmanman.mapper"/>
</mappers>
<!-- 本文的代码便是用的这个 -->
以上配置会告诉 MyBatis 去哪里找映射文件,剩下的细节就应该是每个 SQL 映射文件了;
XML映射器
MyBatis 的真正强大之处便是它的语句映射,也时因为映射的强大,映射器的XML文件就显得相对简单;
本文中只列出sql 中最常使用的四个元素:
- select 映射查语句
- update 映射更新语句
- insert 映射插入语句
- delete 映射删除语句
select
MyBatis 的基本原则之一便是:在每个插入、更新或删除操作之间,通常会执行多个查询操作。例如本文中的 select 查询语句:
<select id="findAll" parameterType="UserInfo" resultType="UserInfo">
select * from user
<where>
<choose>
<when test="null != user_id">
and user_id=#{user_id}
</when>
<otherwise>
<if test="null != user_name">
and user_name=#{user_name}
</if>
<if test="null != user_gender">
and user_gender=#{user_gender}
</if>
<if test="null != user_province">
and user_province=#{user_province}
</if>
<if test="null != user_balance">
and #{user_balance}>=user_balance
</if>
</otherwise>
</choose>
</where>
</select>
这个语句的名为 findAll,接受了一个 USerInfo 对象类型的参数,并返回了一个 UserInfo 对象类型的对象。
注意参数符号:
#{user_id}
这就告诉了 MyBatis 创建了一个预处理语句(parameterStatement)参数,在 JDBC 中,这样的一个参数在SQL 中会由一个 " ? "来标识;
select 元素属性
属性 | 说明 | |
---|---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句(namespace + id 关联唯一对应的方法) | |
parameterType | 将会传入这条语句的参数的类全限定名或别名,简单的来说就是输入参数的类型 | |
resultType | 期望从这条语句中返回结果的类全限定名或别名,简单的来说就是输出参数的类型 | |
resultMap | 对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个 | |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false | |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动) | |
fetchSize | 设置每次批量返回结果行数的值,默认值为未设置(unset)(依赖数据库驱动) | |
… | …(未常用的就没有列出了…) |
insert,update 和 delete
数据变更语句 insert,update 和 delete 的实现非常接近,故放在一起展示了:
Insert, Update, Delete 元素的属性
属性 | 说明 | |
---|---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句(namespace + id 关联唯一对应的方法) | |
parameterType | 将会传入这条语句的参数的类全限定名或别名,简单的来说就是输入参数的类型 | |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:true | |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动) | |
statementType | 可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED | |
keyProperty | 仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset )。如果生成列不止一个,可以用逗号分隔多个属性名称 | |
keyColumn | (仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称 | |
useGeneratedKeys | (仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false | |
本文四种操作代码说明:
<!-- select | insert | update | delete id:捆绑 Mapper 接口中的方法名称-->
<!-- parameterMap | resultMap 为了修正实体类的属性和数据表中字段名称,类型,数量不一致而存在的 -->
<!-- parameterType | resultType 直接关联实体类型 -->
<!-- 简单固定的where 条件:where field=value and .... -->
<!-- 复杂动态的where 条件:<where></where> 1、无条件时不添加where,多条件时自动去除第一个and-->
<!-- 复杂动态的update 条件:<set></set> 多修改时自动取出最后一个逗号-->
<!-- 单分支:<if test="CONDITION"></if> -->
<!-- 多分支:<choose> <when test="COND01"></when> ... <otherwise></otherwise></choose> -->
<!-- 条件表达式不能出现 < | <= :与标签语法冲突 -->
<!-- parameterType: 非基本类型 array | list | map -->
<!-- 循环:<foreach collection="array | list | map" item="alias" open="BEGIN_SIGN" close="END_SIGN" separator="SEP_SIGN" index=ix>
#{user.alias},#{user.ix}
</foreach> -->
<!-- autoMapping 自动映射:一般关闭,自定义映射关系 ,解决数量不一致 -->
<resultMap id="userMap" type="UserInfo" autoMapping="false">
<!-- 名称不一致 -->
<result column="use_account" property="userAccount" />
<!-- 类型不一致 -->
<result column="use_balance" jdbcType="DECIMAL" property="userBalance" javaType="java.math.BigDecimal" />
</resultMap>
执行四种操作说明:
APP 启动后,会去优先加载静态资源包(resources)下面的静态文件(mybatis.xml …)至堆内存(项目共享内存),根据mybatis.xml 中的 mappers 配置项去寻找对应的映射文件:
-
resource —>userMapper.xml --(xml中设置的namespace)–>UserMapper.java
-
class —> UserMapper.java --(相同的结构体系)–>userMapper.xml
-
package —>UserMapper.java --(相同的结构体系)–>userMapper.xml
找到之后,根据APP中调用接口类UserMapper.java 的四种操作,去xml 文件中去SQL 映射文件,操作需要实体类则调用,无须则不调用(eg:实操中删除操作就不需要用到实体UserInfo.java),数据出来之后则根据APP处理逻辑操作至接结束。
注:在相同的结构体系下,接口类一般标准的java命名规则,首字母大写的驼峰(UserMapper),而在静态资源包里项目体系的xml文件命名则为首字母小写的驼峰(userMapper),别问为什么,问就是潜规则!!!
Author: 洋群满满
Category:Java