1 mybatis介绍
- MyBatis本是Apache软件基金会的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了Google Code,并且改名为MyBatis 。2013年11月迁移到Github。
- MyBatis是一个优秀的基于Java的持久层框架,其主要思想是将程序中大量SQL语句剥离出来,配置在配置文件中,实现SQL的灵活配置。使得SQL与程序代码分离,可以在不修改程序代码的情况下,直接在配置文件中修改SQL。
- MyBatis对原有JDBC操作进行了封装,几乎消除了所有JDBC代码,使开发者只需关注 SQL 本身。
- MyBatis可以使用简单的XML或Annotation来配置执行SQL,并自动完成ORM操作,将执行结果返回
2 MyBatis环境搭建
2.1 pom.xml中引入MyBatis核心依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--项目配置-->
<groupId>com.qf</groupId>
<artifactId>hello-mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<!--依赖-->
<dependencies>
<!--MyBatis核心依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--MySql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
</project>
2.2 创建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">
<!--MyBatis配置-->
<configuration>
<!--JDBC环境配置、选中默认环境-->
<environments default="MySqlDB">
<!--MySql数据库环境配置-->
<environment id="MySqlDB">
<!--事务管理-->
<transactionManager type="JDBC"/>
<!--连接池-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!-- &转义& -->
<property name="url" value="jdbc:mysql://localhost:3306/x?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="xxx"/>
<property name="password" value="xxx"/>
</dataSource>
</environment>
</environments>
<!--Mapper注册-->
<mappers>
<!--注册Mapper文件的所在位置-->
<mapper resource="xxxMapper.xml"/>
</mappers>
</configuration>
MyBatis配置文件是SQL映射文件,其中有很多元素节点,下面介绍一下这些节点:
mapper:映射文件的根元素节点,只有一个属性namespace(命名空间),作用:用于区分不同的mapper,全局唯一。绑定DAO接口,即面向接口编程。当namespace绑定某一接口之后,可以不用写该接口的实体类,MyBatis会通过接口的完整限定名查找到对应的mapper配置来执行SQL语句。因此namespace的命名必须要和接口同名。
cache:配置给定命名空间的缓存。(性能较低,不推荐使用)
resultMap:用来描述数据库结果集和对象的对应关系。
sql:可以重用的SQL块,也可以被其他语句引用。
insert:映射插入语句。
update:映射更新语句。
delete:映射删除语句。
select:映射查询语句。
namespace的命名必须跟某个DAO接口同名,通属于DAO层,所以映射文件与该DAO接口应放置在同一package下。
在不同的mapper文件中,子元素的id可以相同,MyBatis通过namespace和子元素的id联合区分。接口中的方法与映射文件中的SQL语句id应一一对应。
resultType
resultType直接表示返回类型,包括基础数据类型和复杂数据类型。
resultMap
id属性:唯一标识,此id值用于select元素的resultMap属性的引用。
type属性:表示该resultMap的映射结果类型。
result子节点:用于标识一些简单属性,其中column属性表示从数据库中查询的字段名,property则表示查询出来的字段对应的值赋给实体对象的哪个属性。
resultMap是对外部resultMap定义的引用,对应外部resultMap的id,表示返回结果映射到某一个resultMap上。主要应用:数据库字段信息与对象属性不一致或者需要做复杂的联合查询以便自由控制映射结果。
resultType和resultMap本质上是一样的,都是Map数据结构。但是不能同时存在,只是二者选其一使用。
association
association:映射到JavaBean的某个复杂类型属性,即JavaBean内部嵌套一个复杂数据类型属性。association仅处理一对一的关联关系。
属性:
javaType:完整Java类名或者别名。
property:映射数据库列的实体对象的属性。
id
result:
property:映射数据库列的实体对象的属性。
column:数据库列名或别名。
collection
collection元素的作用和association元素的作用类似,只不过collection元素映射的属性是一个集合列表,即JavaBean内部嵌套一个复杂数据类型(集合)属性。
属性:
ofType:完整Java类型或者别名,即集合所包含的类型。
property:映射数据库列的实体对象的属性。
collection的子元素与association基本一致。
3 mybatis入门程序
3.1 创建数据库表
create table t_users(
id int primary key auto_increment,
name varchar(50),
password varchar(50),
sex varchar(1),
birthday birthday,
registTime datetime
)default charset = utf8;
3.2 定义所需CURD操作的实体类
package com.qf.mybatis.part1.basic;
public class User {
private Integer id;
private String name;
private String password;
private String sex;
private Date birthday;
private Date registTime;
//无参构造(必备构造二选一)
public User() {}
//全参构造(必备构造二选一)
public User(Integer id, String name, String password, String sex, Date birthday, Date registTime) {
this.id = id;
this.name = name;
this.password = password;
this.sex = sex;
this.birthday = birthday;
this.registTime = registTime;
}
//Getters And Setters
}
3.3 定义DAO接口
package com.qf.mybatis.part1.basic;
public interface UserDao {
public User selectUserById(Integer id);
}
3.4 编写DAO对应的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">
<!--namespace = 所需实现的接口全限定名-->
<mapper namespace="com.qf.mybatis.part1.basic.UserDao">
<!--id = 所需重写的接口抽象方法,resultType = 查询后所需返回的对象类型-->
<select id="selectUserById" resultType="com.qf.mybatis.part1.basic.User">
<!--#{arg0} = 方法的第一个形参-->
SELECT * FROM t_users WHERE id = #{arg0}
</select>
</mapper>
3.5 将Mapper.xml注册到mybatis-config.xml中
<!--Mapper文件注册位置-->
<mappers>
<!--注册Mapper文件-->
<mapper resource="UserDaoMapper.xml"/>
</mappers>
3.6 编写测试类
package com.qf.mybatis.part1.basic;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class HelloMyBatis {
@Test
public void test1() throws IOException {
//1.获得读取MyBatis配置文件的流对象
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.构建SqlSession连接对象的工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂获得连接对象
SqlSession sqlSession = factory.openSession();
//4.通过连接对象获得接口实现类对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
//5.调用接口中的方法
System.out.println(userDao.selectUserById(1));
}
}
4 MyBatis的CRUD操作
4.1 查询以及参数绑定方式
4.1.1 序号绑定参数
public interface UserDao {
//使用原生参数绑定
public User selectUserByIdAndPwd(Integer id , String pwd);
}
<select id="selectUserByIdAndPwd" resultType="user">
SELECT * FROM t_users
WHERE id = #{arg0} AND password = #{arg1} <!--arg0 arg1 arg2 ...-->
</select>
<select id="selectUserByIdAndPwd" resultType="user">
SELECT * FROM t_users
WHERE id = #{param1} AND password = #{param2} <!--param1 param2 param3 ...-->
</select>
4.1.2 注解绑定参数
import org.apache.ibatis.annotations.Param; //引入注解
public interface UserDao {
//使用MyBatis提供的@Param进行参数绑定
public User selectUserByIdAndPwd(@Param("id") Integer id , @Param("pwd") String pwd);
}
<select id="selectUserByIdAndPwd" resultType="user">
SELECT * FROM t_users
WHERE id = #{id} AND password = #{pwd} <!-- 使用注解值 @Param("pwd") -->
</select>
4.1.3 Map绑定参数
public interface UserDao {
//添加Map进行参数绑定
public User selectUserByIdAndPwd_map(Map values);
}
Map values = new HashMap(); //测试类创建Map
values.put("myId",1); //自定义key,绑定参数
values.put("myPwd","123456");
User user = userDao.selectUserByIdAndPwd_map(values);
<select id="selectUserByIdAndPwd_map" resultType="user">
SELECT * FROM t_users
WHERE id = #{myId} AND password = #{myPwd} <!-- 通过key获得value -->
</select>
4.1.4 对象绑定参数
public interface UserDao {
//使用对象属性进行参数绑定
public User selectUserByUserInfo(User user);
}
<select id="selectUserByUserInfo" resultType="user">
SELECT * FROM t_users
WHERE id = #{id} AND password = #{password} <!-- #{id}取User对象的id属性值、#{password}同理 -->
</select>
4.2 删除
public interface UserDao {
public void deleteUser(int id);
}
<delete id="deleteUser" parameterType="int">
DELETE FROM t_users
WHERE id = #{id} <!--只有一个参数时,#{任意书写}-->
</delete>
4.3 修改
public interface UserDao {
public void updateUser(String name, String password,String sex,Birthday birthday);
}
<update id="updateUser" parameterType="user">
UPDATE t_users SET name=#{name}, password=#{password}, sex=#{sex}, birthday=#{birthday}
WHERE id = #{id} <!--方法参数为对象时,可直接使用#{属性名}进行获取-->
</update>
4.4 添加
public interface UserDao {
public void insertUser(String name, String password,String sex,Birthday birthday);
}
<!--手动主键-->
<insert id="insertUser" parameterType="user">
INSERT INTO t_users VALUES(#{id},#{name},#{password},#{sex},#{birthday},NULL);
</insert>
<!--自动主键-->
<insert id="insertUser" parameterType="user">
<!-- 自动增长主键,以下两种方案均可 -->
INSERT INTO t_users VALUES(#{id},#{name},#{password},#{sex},#{birthday},NULL);
INSERT INTO t_users VALUES(NULL,#{name},#{password},#{sex},#{birthday},NULL);
</insert>
5 ORM映射
MyBatis只能自动维护库表”列名“与”属性名“相同时的一一对应关系,二者不同时,无法自动ORM。
5.1 方案一:列的别名
在SQL中使用 as 为查询字段添加列别名,以匹配属性名。
<mapper namespace="com.qf.mybatis.part2.orm.ManagerDao">
<select id="selectManagerByIdAndPwd" resultType="com.qf.mybatis.part2.orm.Manager">
SELECT mgr_id AS id , mgr_name AS username , mgr_pwd AS password
FROM t_managers
WHERE mgr_id = #{id} AND mgr_pwd = #{pwd}
</select>
</mapper>
5.2 方案二:结果映射(ResultMap - 查询结果的封装规则)
通过< resultMap id="" type="" >映射,匹配列名与属性名。
<mapper namespace="com.qf.mybatis.part2.orm.ManagerDao">
<!--定义resultMap标签-->
<resultMap id="managerResultMap" type="com.qf.mybatis.part2.orm.Manager">
<!--关联主键与列名-->
<id property="id" column="mgr_id" />
<!--关联属性与列名-->
<result property="username" column="mgr_name" />
<result property="password" column="mgr_pwd" />
</resultMap>
<!--使用resultMap作为ORM映射依据-->
<select id="selectAllManagers" resultMap="managerResultMap">
SELECT mgr_id , mgr_name , mgr_pwd
FROM t_managers
</select>
</mapper>
6 MyBatis 中 #{} 和 ${} 的区别
#{}: 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,一个 #{ } 被解析为一个参数占位符” 。
:
仅
仅
为
一
个
纯
碎
的
s
t
r
i
n
g
替
换
,
在
动
态
S
Q
L
解
析
阶
段
将
会
进
行
变
量
替
换
。
以
{}: 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。以
:仅仅为一个纯碎的string替换,在动态SQL解析阶段将会进行变量替换。以{}格式传入入参后的执行sql打乱了我们的预期sql格式及查询条件,从而实现sql注入。如:select * from user where id= $ {user_id},如果传入的值是11,那么解析成sql时的值为where id=11