MyBatis的前世今生
MyBatis的前身就是iBatis,iBatis本是由Clinton Begin开发,后来捐给Apache基金会,成立了iBatis开源项目。2010年5月该项目由Apahce基金会迁移到了Google Code,并且改名为MyBatis。
MyBatis从3.0开始,3.0之前为iBatis
Mybatis介绍
MyBatis是一个数据持久层(ORM)框架,在实体类和SQL语句之间建立映射关系,是一种半自动化的ORM实现。
- (ORM)类对象对应数据库的表
MyBatis的优点:1、基于SQL语法,简单易学。2、能了解底层组装过程。 3、SQL语句封装在配置文件中,便于统一管理与维护,降低了程序的耦合度。4、程序调试方便。
与传统JDBC的比较
最简单的持久化框架
架构级性能增强
SQL代码从程序代码中彻底分离,可重用
增强了项目中的分工
增强了移植性
MyBatis工作流程
MyBatis基本要素
1、conf.xml 全局配置文件
2、mapper.xml 核心映射文件
3、SqlSession接口
创建MyBatis的基本要素
**创建一个maven项目(所有资源文件放在resouce目录下):
所需依赖:
<dependencies>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- jdbc驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
<scope>provided</scope>
</dependency>
</dependencies>
properties文件**
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3307/jsd2101?useUnicode=true&characterEncoding=utf-8&useSSL=false
1.conf.xml 全局配置文件
<?xmZ 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="db.properties"/>
<settings>
<!--打印sql日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--使用字段下划线转换成驼峰命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<!--指定别名-->
<typeAlias type="com.entity.User" alias="user"/>
<!--指定包下的所有类名以简写作为别名,不区分大小写-->
<package name="com.entity"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<!--多个参数用&隔开,在xml文件需要转义成 & properties文件直接用&符号即可-->
<property name="url"
value="jdbc:mysql://localhost:3306/jsd2101?useUnicode=true&characterEncoding=utf-8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--将xml文件的mapper加载到该xml文件中-->
<mappers>
<mapper resource="mapping/UserMapper.xml"/>
</mappers>
</configuration>
<!--
<configuration>:声明在标签里面的信息是配置信息
<typeAliases>:声明在该标签里面的信息是一个个的别名
<typealias>:声明要使用别名的对象(全路径)用java注解的话可以使用@Alias注解声明
<environments>:声明在该标签内的环境变量,default表示默认的环境变量,一个environment表示一个jdbc连接数据库,如果有很多数据库的话我们要用到不同的环境变量
<environment>:声明环境变量
<transactionManager>:声明事务管理器 它的类型(type)有:JDBC(基于jdbc的事务) 还有 MANAGED(托管的事务)
<dataSource>:声明数据源,数据源的类型有NOPOOLED ,POOLED ,还有JIDN,在数据量少的话用ONPOOLED,测试和开发过程一般用POOLED,实际运行使用JIDN
<property>:jdbc连接的一些属性
<mappers>:声明我们定义的一个个Mapper类,或者说是关联
<mapper>:声明Mapper的路径
————————————————
版权声明:本文为CSDN博主「sweetException」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/YQYnsmile/article/details/52807815
-->
2.mapper.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="user">
<!--
parameterType="int",传递的参数类型,只传一个数据时可省略
参数类型的名称可以为全限定名也可以为指定的别名基本类型可以直接写(int,long、、、),集合数组等类型(java.util.Arrays对应arrays、、)封装有别名。
#{id}相当于参数的占位符名称
一个参数时,id可任意名称
resultType="com.entity.User"是返回值类型,不能省略,执行sql语句结果封装(根据属性名和表的字段名对应赋值)到该类型类型
-->
<select id="queryById" parameterType="int" resultType="com.entity.User">
select * from User where id = #{id}
</select>
<!--
数据类型默认为全限定名,可以取别名取代不区分大小写(在全局配置文件内设置)
从参数对象中获取对应的值。
now()为mysql的获取当前时间函数
keyProperty="id" useGeneratedKeys="true", 获取mysql自动增长的id值,回填到参数的对象上。
-->
<insert id="add" parameterType="user" keyProperty="id" useGeneratedKeys="true">
insert into user(name,username,password,sex,age,birthday,create_time)
values (#{name},#{username},#{password},#{sex},#{age},#{birthday},now())
</insert>
<!--parameterType="list"可省略-->
<!--
遍历集合元素,将集合内的对象以逗号隔开
结果为:insert into user(user) values(user1),(user2)...
-->
<insert id="addMore" parameterType="list">
insert into user(name,username,password,sex,age,birthday,create_time)values
<foreach collection="list" item="user" separator=",">
(#{user.name},#{user.username},#{user.password},#{user.sex},#{user.age},#{user.birthday},now())
</foreach>
</insert>
<delete id="deleteById" parameterType="int">
delete from user where id = #{id}
</delete>
<!--
遍历数组:以"("开始,以")"结束,内容为每个item对象,每个对象以逗号隔开。
例如:String[] a = {"1","2","3"},结果(1,2,3)
-->
<!--如果是#{},是占位符,根据传递的参数类型自动添加''号,最终wei ('1,2,3,4') 5.5版本的mysql会删除第一个数据,5.7则会报错-->
<!--${}为字符串拼接,直接将数据拼接进去-->
<delete id="deleteByIds" parameterType="String">
delete from user where id in <foreach collection="array" item="ids" open="(" close=")" separator=",">#{ids}</foreach>
<!--delete from user where id in (${ids})-->
</delete>
<!--set标签自动去掉多余的逗号-->
<!--if标签判断为true时,将内容写入-->
<update id="update" parameterType="user">
update user
<set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="username!=null and username!=''">
username=#{username},
</if>
<if test="password!=null and password!=''">
password=#{password},
</if>
<if test="sex!=null and sex!=''">
sex=#{sex},
</if>
<if test="age!=null and age!=''">
age=#{age},
</if>
<if test="birthday!=null and birthday!=''">
birthday=#{birthday},
</if>
</set>
where id=#{id}
</update>
<!--多个数据时,用Map进行传值,根据键值来获取对应的值。-->
<!--返回的为List<user>类型,标签会自动根据类型将值放入list集合返回-->
<select id="queryByPage" parameterType="map" resultType="user">
SELECT * from user LIMIT #{pageNum},#{pageSize}
</select>
<!-- #{} 为占位符自动为值添加'',${}为字符串拼接 -->
<!-- where 标签自动删除多余的and -->
<select id="queryByCondition" parameterType="user" resultType="user">
select * from user
<where>
<if test="name != null and name!=''">
and name like '%${name}%'
</if>
<if test="username != null and username!=''">
and username like concat('%',#{username},'%')
</if>
</where>
</select>
<!--自定义要查询的列-->
<sql id="main_clu">
id,name,username
</sql>
<!--将自定义的sql引入-->
<select id="queryByName">
select <include refid="main_clu"/> from user where name = #{name}
</select>
foreach语句中, collection属性的参数类型可以使:List、数组、map集合
collection: 必须跟mapper.java中@Param标签指定的元素名一样
item: 表示在迭代过程中每一个元素的别名,可以随便起名,但是必须跟元素中的#{}里面的名称一样。
index:表示在迭代过程中每次迭代到的位置(下标)
open:前缀, sql语句中集合都必须用小括号()括起来
close:后缀
separator:分隔符,表示迭代时每个元素之间以什么分隔
<select id="queryInName">
select <include refid="main_clu"/> from user where name in
<foreach collection="names" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach> t2
</select>
</mapper>
给mapper命名空间,防止以后导入全局配置文件时id相同。
DaoImpl
public class UserDaoImpl implements UserDao {
public int add(User user) {
SqlSession session = MybatisUtil.getSession();
//打印自动增长的id值
System.out.println(user.getId());
//默认返回更新行数
int i = session.insert("user.add", user);
session.commit();
return i;
}
public int addMore(List<User> list) {
SqlSession session = MybatisUtil.getSession();
int i = session.update("user.addMore", list);
session.commit();
return i;
}
public int deleteById(Integer id) {
SqlSession session = MybatisUtil.getSession();
int i = session.delete("user.deleteById", id);
session.commit();
return i;
}
public int deleteByIds(String[] ids) {
SqlSession session = MybatisUtil.getSession();
int i = session.delete("user.deleteByIds", ids);
session.commit();
return i;
}
public User queryById(Integer id) {
SqlSession session = MybatisUtil.getSession();
User user = (User) session.selectOne("user.queryById", 1);
return user;
}
public List<User> queryPage(Integer pageNum, Integer pageSize) {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("pageNum", pageNum);
map.put("pageSize", pageSize);
SqlSession session = MybatisUtil.getSession();
List<User> list = session.selectList("queryByPage", map);
return list;
}
public List<User> Like(User user) {
SqlSession session = MybatisUtil.getSession();
List<User> list = session.selectList("user.like", user);
return list;
}
}
使用
public class Test {
public static void main(String[] args) {
try {
//加载mybatis的核心配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//获取会话创建工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建会话对象,相当于jdbc的connection对象,代表每一次数据库连接
SqlSession session = sqlSessionFactory.openSession();
//调用数据库的方法
User user = (User) session.selectOne("user.queryById", 1);
System.out.println(user);
//关闭对象,释放内存
session.close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用接口的方式调用映射文件的SQL语句(去掉DaoImpl)和封装会话
简单的SQL语句用注解来写,复杂的SQL语句用xml来写。
会话封装
public class MybatisUtil {
private static SqlSessionFactory sf;
static {
try {
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
sf = new SqlSessionFactoryBuilder().build(reader);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSession() {
return sf.openSession();
}
public static void Close(SqlSession sqlSession) {
if (sqlSession != null) {
sqlSession.close();
}
}
}
Test
public class Test4 {
public static void main(String[] args) {
SqlSession session = MybatisUtil.getSession();
//采用接口的方式操作数据,传入接口字节码类,无需自己创建实现类,程序动态创建该接口的代理实现对象
// 根据接口所在的全路径名查找对应的映射文件,调用接口方法时,根据方法的名称查找映射文件对应的id
UserDao userDao = session.getMapper(UserDao.class);
User user = userDao.queryById(11);
System.out.println(user);
}
}
注意:映射文件的命名空间必须为全限定名!,Sql语句的id对应方法名称
使用注解来写SQL
SQL语句跟配置文件写法一样
public interface UserDao {
//一个参数不用指定参数名称
@Delete("delete from user where id = #{id}")
//多个参数时,需要指定参数名称,@Param可以指定参数名称
public List<User> queryByPage(@Param("pageNum") Integer pageNum,@Param("pageSize") Integer pageSize);
}
对应的SQL用对应的注解
使用方法:
public class Test4 {
public static void main(String[] args) {
SqlSession session = MybatisUtil.getSession();
//采用接口的方式操作数据,传入接口字节码类,无需自己创建实现类,程序动态创建该接口的代理实现对象
// 根据接口所在的全路径名查找对应的映射文件,调用接口方法时,根据方法的名称查找映射文件对应的id
UserDao userDao = session.getMapper(UserDao.class);
userDao.deleteById(6);
session.commit();
}
}
不使用mapper.xml 核心映射文件,使用注解方式配置映射文件关系
public interface UserMapper {
@Select("select * from user where id=#{id}")
public User queryById(Integer id);
}
核心配置文件
<mappers>
<!--使用注解方式配置映射文件关系,加载接口文件路径,或者存放接口文件的包名-->
<mapper class="com.mapper.UserMapper"/>
<!--<package name="com.mapper"/>-->
</mappers>
MyBatis多表查询
简单的SQL语句用注解来写,复杂的SQL语句用xml来写。
Java类:
User类
@Data//自动生成get()、set()、hashCode()、toString()、、、
@NoArgsConstructor//生成无参构造方法
@AllArgsConstructor//生成全参的构造方法
public class User {
private Integer id;
private String name;
private String username;
private String password;
private Integer sex;
private Integer age;
private Date birthday;
private Timestamp createTime;
/**
* 一对多,在一方添加多方的对象的集合属性
*/
private List<Order> orders;
}
Order类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private Integer id;
private Integer price;
private Timestamp createTime;
/**
* 多对一关联关系,在多方对象中添加一方类型属性
*/
private User user;
private List<OrderItem> orderItems;
}
Product类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
private Integer id;
private String name;
private Integer price;
private List<OrderItem> orderItems;
}
OrderItem类
public class OrderItem {
private Integer id;
/**
* 多对一
*/
private Order order;
/**
* 多对一
*/
private Product product;
}
xml配置文件
OrderMapper.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.dao.OrderDao">
<!--
当返回值有多个象时用resultMap标签,id为标签命名,返回类型为order类型(重命名了)
id标签和result标签一样都是用来赋值的,在规范上id标签作用于主键,result标签作用于普通属性,property为属性名,column为SQL的字段名(注意:字段重名时重命名)
association标签用于多对一时,给OrderMap类内的user属性赋值:property为属性名,javaType为属性的类型(User重命名了)
都是调用set方法写进去的
-->
<resultMap id="OrderMap" type="order">
<id property="id" column="id"/>
<result property="price" column="price"/>
<result property="createTime" column="otime"/>
<association property="user" javaType="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="name" column="name"/>
<result property="password" column="password"/>
<result property="sex" column="sex"/>
<result property="birthday" column="birthday"/>
<result property="createTime" column="create_time"/>
</association>
</resultMap>
<resultMap id="UserMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="name" column="name"/>
<result property="password" column="password"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="birthday" column="birthday"/>
<result property="createTime" column="create_time"/>
<!-- 一对多 ofType为list内的类型 注意主键不要重名否则无法收入相同主键的值 -->
<collection property="orders" ofType="order">
<id property="id" column="id"/>
<result property="price" column="price"/>
<result property="createTime" column="otime"/>
</collection>
</resultMap>
<select id="queryUserByOrderId" resultMap="OrderMap">
select o.id oid,
o.price,
o.create_time otime,
u.*
from user u,order_ o
where u.id=o.user_id and o.id=#{oid}
</select>
<select id="queryOrderByUserId" resultMap="OrderMap">
select o.id oid,
o.price,
o.create_time otime,
u.*
from user u,order_ o
where u.id=o.user_id and u.id=#{uid}
</select>
<select id="queryByUserId" resultMap="UserMap">
select o.id oid,
o.price,
o.create_time otime,
u.*
from user u,order_ o
where u.id=o.user_id and u.id=#{uid}
</select>
</mapper>
ProductMapper.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.dao.ProductDao">
<resultMap id="UserOrderProductMap" type="user">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="birthday" column="birthday"/>
<result property="createTime" column="create_time"/>
<collection property="orders" ofType="Order">
<id property="id" column="oid"/>
<result property="price" column="oprice"/>
<result property="createTime" column="otime"/>
<collection property="orderItems" ofType="OrderItem">
<id property="id" column="id"/>
<association property="product" javaType="Product">
<id property="id" column="pid"/>
<result property="price" column="pprice"/>
<result property="name" column="pname"/>
</association>
</collection>
</collection>
</resultMap>
<select id="queryProductByOrderId">
select
from product p,order_item oi
where oi.product_id = p.id
</select>
<select id="queryProductByUserId">
</select>
<select id="queryUserAndOrderAndProductByUserId" resultMap="UserOrderProductMap">
select u.id,
u.name,
u.username,
u.password,
u.sex,
u.age,
u.birthday,
u.create_time,
o.id oid,
o.price oprice,
o.create_time otime,
p.id pid,
p.name pname,
p.price pprice
from user u,order_ o,order_item oi,product p
where u.id=o.user_id
and o.id=oi.order_id
and oi.product_id = p.id
and u.id=#{id}
</select>
</mapper>
补充lombok
@Data//自动生成get()、set()、hashCode()、toString()、、、
@NoArgsConstructor//生成无参构造方法
@AllArgsConstructor//生成全参的构造方法
public class User {
private Integer id;
private String name;
private String username;
private String password;
private Integer sex;
private Integer age;
private Date birthday;
private Timestamp createTime;
}
注意:确认idea安装有插件