博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mybatis详解
阅读量:3960 次
发布时间:2019-05-24

本文共 13522 字,大约阅读时间需要 45 分钟。

Mybatis概念

Mybatis是在jdbc的基础之上封装而成的开源持久层框架。

Mybatis是一个ORM框架。ORM(object relational mapping):对象关系型映射

Mybatis入门

搭建mybatis环境:

<!-- 设置项目属性 -->

<properties>

<argLine>-Dfile.encoding=UTF-8</argLine>

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

</properties>

<!-- 依赖管理 -->

<dependencies>

<!-- mysql驱动 -->

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>5.1.6</version>

</dependency>

<!-- mybatis框架 -->

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>3.4.5</version>

</dependency>

</dependencies>

设计库表:

create table tbl_user(

uid int(9) primary key,

uname varchar(32),

upass varchar(32),

uage int(3)

);

insert into tbl_user values(1,'admin','123456',24);

创建与表对应的实体类(javabean)

public class UserEntity {

/** 对象标识符(与表中主见对应属性) */

public Integer uid;

/** 用户名 */

public String uname;

/** 密码 */

public String upass;

/** 年龄 */

public Integer uage;

public UserEntity() {}

public UserEntity(Integer uid, String uname, String upass, Integer uage) {

this.uid = uid;

this.uname = uname;

this.upass = upass;

this.uage = uage;

}

 

public Integer getUid() {

return uid;

}

 

public void setUid(Integer uid) {

this.uid = uid;

}

 

public String getUname() {

return uname;

}

 

public void setUname(String uname) {

this.uname = uname;

}

 

public String getUpass() {

return upass;

}

 

public void setUpass(String upass) {

this.upass = upass;

}

 

public Integer getUage() {

return uage;

}

 

public void setUage(Integer uage) {

this.uage = uage;

}

}

mybatis配置文件(配置连接数据库信息)

在src/main/resources下创建mybatisConfig.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="mysqlDB">

<!-- 配置一个数据库连接环境 -->

<environment id="mysqlDB">

<transactionManager type="JDBC"></transactionManager>

<dataSource type="POOLED">

<!-- url -->

<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis"></property>

<!-- name -->

<property name="username" value="root"></property>

<!-- password -->

<property name="password" value="root"></property>

<!-- driver class -->

<property name="driver" value="com.mysql.jdbc.Driver"></property>

</dataSource>

</environment>

</environments>

<!-- load mapping file -->

<mappers>

<mapper resource="mapper/UserEntityMapper.xml"></mapper>

</mappers>

</configuration>

mybatis映射文件

<?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.offcn.mybatis.entity">

<!-- insert -->

<insert id="insertUser">

insert into tbl_user values(2,'scott','tiger',25)

</insert>

</mapper>

常用API

public class TestMybatis {

public static void main(String[] args) throws IOException {

// 加载配置文件

Reader reader = Resources.getResourceAsReader("mybatisConfig.xml");

// 创建构造器对象

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

// 创建工厂

SqlSessionFactory sqlSessionFactory = builder.build(reader);

//创建执行对象

SqlSession session = sqlSessionFactory.openSession();

// 执行sql语句

session.insert("insertUser");

// 提交事务

session.commit();

session.close();

}}

向SQL语句传参方式

(1)传对象

<!-- update -->

<update id="updateUser" parameterType="UserEntity">

update tbl_user set

uname=#{uname},upass=#{upass},uage=#{uage} where uid=#{uid}

</update>

(2)传map对象

/** queryMap */

@Test

public void queryMap() {

// 构造条件

Map<String, Object> map = new HashMap<String, Object>();

map.put("name", "scott");

map.put("password", "tiger");

// 创建执行对象

SqlSession session = sqlSessionFactory.openSession();

// 执行sql语句

List<UserEntity> list = session.selectList("queryMap", map);

for (UserEntity user : list) {

System.out.println(user);

}

session.close();

}

<!-- 根据用户名和密码查询 -->

<select id="queryMap" resultType="UserEntity" parameterType="java.util.Map">

SELECT uid,uname,upass,uage from tbl_user where uname=#{name} and upass=#{password}

</select>

(3)直接传变量

@Test

public void queryById() {

// 创建执行对象

SqlSession session = sqlSessionFactory.openSession();

// 执行sql语句

UserEntity user = (UserEntity) session.selectOne("queryById", 5);

System.out.println(user);

session.close();

}

<select id="queryById" parameterType="int" resultType="UserEntity">

SELECT uid,uname,upass,uage from tbl_user where uid=#{uid}

</select>

(4)#与$区别

1.区别

#{}:占位符号,预编译sql,防止sql注入

${}:sql拼接符号,从参数中取值,构造静态sql语句

2.具体分析

动态 SQL 是 mybatis 的强大特性之一,也是它优于其他 ORM 框架的一个重要原因。mybatis 在对 sql 语句进行预编译之前,会对 sql 进行动态解析,解析为一个 BoundSql 对象,也是在此处对动态 SQL 进行处理的。在动态 SQL 解析阶段,  #{ } 和 ${ } 会有不同的表现。

#{ }:解析为一个 JDBC 预编译语句(prepared statement)的参数标记符。

例如,Mapper.xml中如下的 sql 语句:

select * from user where name = #{name};

动态解析为:

select * from user where name = ?;

一个 #{ } 被解析为一个参数占位符 ? 。

而${ }仅仅为一个纯粹的 string 替换,在动态 SQL 解析阶段将会进行变量替换。

例如,Mapper.xml中如下的 sql:

select * from user where name = ${name};

当我们传递的参数为 "Jack" 时,上述 sql 的解析为:

select * from user where name = "Jack";

预编译之前的 SQL 语句已经已经是常量数据了。 综上所得, ${ } 变量的替换阶段是在动态 SQL 解析阶段,而 #{ }变量的替换是在 DBMS(数据库管理系统) 中

3.用法

能使用 #{ } 的地方尽量用 #{ }

首先这是为了性能考虑的,相同的预编译 sql 可以重复利用。其次,${ } 在预编译之前已经被变量替换了,这会存在 sql 注入问题。例如,如下的 sql:

select * from ${tableName} where name = #{name}

假如,我们的参数 tableName 为 user; delete user; --,那么 SQL 动态解析阶段之后,预编译之前的 sql 将变为:

select * from user; delete user; -- where name = ?;

-- 之后的语句将作为注释,不起作用,因此本来的一条查询语句偷偷的包含了一个删除表数据的 SQL。

表名作为变量时,必须使用 ${ }

这是因为,表名是字符串,使用 sql 占位符替换字符串时会带上单引号 '',这会导致 sql 语法错误,例如:

select * from #{tableName} where name = #{name};

 预编译之后的sql 变为:

select * from ? where name = ?;

假设我们传入的参数为 tableName = "user" , name = "Jack",那么在占位符进行变量替换后,sql 语句变为:

select * from 'user' where name='Jack';

上述 sql 语句是存在语法错误的,表名不能加单引号 ''(注意,反引号 ``是可以的)。

4.sql预编译

 1. 定义:

sql 预编译指的是数据库驱动在发送 sql 语句和参数给 DBMS 之前对 sql 语句进行编译,这样 DBMS 执行 sql 时,就不需要重新编译。

 2. 为什么需要预编译

JDBC 中使用对象 PreparedStatement 来抽象预编译语句,使用预编译。预编译阶段可以优化 sql 的执行。预编译之后的 sql 多数情况下可以直接执行,DBMS 不需要再次编译。预编译语句对象可以重复利用,把一个 sql 预编译后产生的 PreparedStatement 对象缓存下来,下次对于同一个sql,可以直接使用这个缓存的 PreparedState 对象。mybatis 默认情况下,将对所有的 sql 进行预编译。

常用库表操作

  1. 添加数据

<!-- insert -->

<insert id="insertUser">

insert into tbl_user values(4,'scott','tiger',25)

</insert>

<!-- insert with param -->

<insert id="insertUserWithParam" parameterType="com.offcn.mybatis.entity.UserEntity">

insert into tbl_user(uid,uname,upass,uage) values(#{uid},#{uname},#{upass},#{uage})

</insert>

 

@Test

public void insertUser() {

// 创建执行对象

SqlSession session = sqlSessionFactory.openSession();

// 执行sql语句

session.insert("insertUser");

// 提交事务

session.commit();

session.close();

}

 

/** 传递对象 */

@Test

public void insertUserWithParam() {

UserEntity user = new UserEntity(6, "张无忌", "qkdny", 21);

// 创建执行对象

SqlSession session = sqlSessionFactory.openSession();

// 执行sql语句

session.insert("insertUserWithParam", user);

// 提交事务

session.commit();

session.close();

}

 

使用实体类别名:

<typeAliases>

<!-- 设置实体类别名 -->

<typeAlias type="com.offcn.mybatis.entity.UserEntity" alias="UserEntity"></typeAlias>

</typeAliases>

 

<insert id="insertUserWithParam" parameterType="UserEntity">

insert into tbl_user(uid,uname,upass,uage) values(#{uid},#{uname},#{upass},#{uage})

</insert>

  1. 更新数据

<!-- update -->

<update id="updateUser" parameterType="UserEntity">

update tbl_user set uname=#{uname},upass=#{upass},uage=#{uage} where

uid=#{uid}

</update>

  1. 删除数据

<!-- delete -->

<delete id="delUser" parameterType="int">

    delete from tbl_user where uid=#{uid}

</delete>

  1. ID查询

<!-- query id resultType:设定返回值-->

<select id="queryById" parameterType="int" resultType="UserEntity">

 SELECT uid,uname,upass,uage from tbl_user where uid=#{uid}

</select>

 

@Test

public void queryById() {

// 创建执行对象

SqlSession session = sqlSessionFactory.openSession();

// 执行sql语句

UserEntity user =(UserEntity)session.selectOne("queryById", 5);

System.out.println(user);

session.close();

}

  1. 查询全部

<!-- query All -->

<select id="queryAll" resultType="UserEntity">

SELECT uid,uname,upass,uage from tbl_user

</select>

@Test

public void queryAll() {

// 创建执行对象

SqlSession session = sqlSessionFactory.openSession();

// 执行sql语句

List<UserEntity> list=session.selectList("queryAll");

for(UserEntity user:list) {

System.out.println(user);

}

session.close();

}

(6)模糊查询

<!-- like -->

<select id="queryLikeOne" resultType="UserEntity" parameterType="string">

SELECT uid,uname,upass,uage from tbl_user where uname like concat('%',#{uname},'%')

</select>

@Test

public void queryLikeOne() {

// 创建执行对象

SqlSession session = sqlSessionFactory.openSession();

// 执行sql语句

List<UserEntity> list=session.selectList("queryLikeOne","无");

for(UserEntity user:list) {

System.out.println(user);

}

session.close();

}

(7)条件查询

@Test

public void queryMap() {

// 构造条件

Map<String, Object> map = new HashMap<String, Object>();

map.put("name", "scott");

map.put("password", "tiger");

// 创建执行对象

SqlSession session = sqlSessionFactory.openSession();

// 执行sql语句

List<UserEntity> list = session.selectList("queryMap", map);

for (UserEntity user : list) {

System.out.println(user);

}

session.close();

}

<!-- 根据用户名和密码查询 -->

<select id="queryMap" resultType="UserEntity" parameterType="java.util.Map">

SELECT uid,uname,upass,uage from tbl_user where uname=#{name} and upass=#{password}

</select>

(8)<sql>标签

用于节点定义sql语句片段

 <!-- 定义sql语句片段 -->

    <sql id="tblUserColumns">uid,uname,upass,uage</sql>使用:

<!-- 根据用户名和密码查询 -->

<select id="queryMap" resultType="UserEntity" parameterType="java.util.Map">

SELECT <include refid="tblUserColumns"></include> from tbl_user where uname=#{name} and upass=#{password}

</select>

(9)<resultMap>标签

resultMap元素是MyBatis中最重要最强大的元素。它就是让你远离需要从结果集中取出数据的JDBC代码的东西,而且在一些情形下允许做一些JDBC不支持的事情。

解决字段名不同问题

如果字段名与属性名不相同,后果?查询结果为空,使用<resultMap>解决。

 <!-- 定义结果集映射 ,type表示结果集要转换的java对象类型-->

    <!-- 结果集映射 -->

<resultMap id="userMap" type="UserEntity">

<!-- 字段与属性匹配 -->

<!-- 主键 -->

        <id property="uid" column="uid"></id>

        <!-- 非主键 -->

        <result property="userName" column="uname"></result>

        <result property="userPass" column="upass"></result>

        <result property="uage" column="uage"></result>

</resultMap>

引用resultMap:

<select id="queryById" parameterType="int" resultMap="userMap">

SELECT

<include refid="tblUserColumns"></include>

from tbl_user where uid=#{uid}

</select>

(10)SqlSessionFactory与SqlSession

1.SqlSessionFactory是线程安全的,在整个程序运行过程中,只一个对象即可,可用通过单例模式创建。

2.SqlSession是线程不安全的,每个线程应拥有一个该对象。它的使用范围请求或方法范围。

 

基于接口实现CRUD

创建接口

/* 用户持久层接口

 * @author Administrator

 */

public interface UserDao {

/**

 * 添加用户

 * @param user

 */

public int insertUser(UserEntity user) throws SQLException;

}

修改映射文件的命名空间

<?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="包名.接口名">      

<insert id="insertUser" parameterType="UserEntity">

insert into

tbl_user(uid,uname,upass,uage)

values(#{uid},#{uname},#{upass},#{uage})

</insert>

</mapper>

获取DAO层对象

// 执行sql语句

UserDao userDao=session.getMapper(UserDao.class);

UserEntity user=new UserEntity(8,"灭绝师太","000000",50);

userDao.insertUser(user);

// 提交事务

session.commit();

session.close();

动态sql语句

 

MyBatis采用功能强大的基于OGNL(对象图形导航语言)的表达式来实现动态sql语句

常用标签

if、choose(when,otherwise)、trim(where,set)、foreach

1.多条件查询

<!-- 动态sql语句 if -->

<select id="dynaIf" parameterType="DeptEntity" resultMap="deptMap">

SELECT <include refid="deptColumns"/> FROM dept where 1=1

<if test="dno>0">

and deptno=#{dno}

</if>

<if test="dname!=null">

and dname=#{dname}

</if>

<if test="dloc!=null">

and loc=#{dloc}

</if>

</select>

<!-- 动态sql语句 choose -->

<select id="dynaChoose" parameterType="DeptEntity" resultMap="deptMap">

SELECT

<include refid="deptColumns" />

FROM dept where 1=1

<choose>

<when test="dno>0">

and deptno=#{dno}

</when>

<when test="dname!=null">

and dname=#{dname}

</when>

<otherwise>

and loc='天津'

</otherwise>

</choose>

</select>

where标签

<!-- 动态sql where where标签如果与and、or的关键字相碰,and、or会被忽略 -->

<!--  where标签 -->

<select id="dynaWhere" parameterType="DeptEntity" resultMap="deptMap">

SELECT

<include refid="deptColumns" />

FROM dept

<where>

<if test="dno>0">

deptno=#{dno}

</if>

<if test="dname!=null">

and dname=#{dname}

</if>

<if test="dloc!=null">

and loc=#{dloc}

</if>

</where>

trim标签

<!--trim标签-->

<!-- 动态sql trim trim标签提供一个where关键字 ,当where关键字与and|or相碰,and or会被忽略 -->

<select id="dynaTrim" parameterType="DeptEntity" resultMap="deptMap">

SELECT

<include refid="deptColumns" />

FROM dept

<trim prefix="where" prefixOverrides="and|or">

<if test="dno>0">

deptno=#{dno}

</if>

<if test="dname!=null">

and dname=#{dname}

</if>

<if test="dloc!=null">

and loc=#{dloc}

</if>

</trim>

</select>

set标签

<!-- 动态sql set -->

<update id="dynaUpdate" parameterType="DeptEntity">

update dept

<set>

<if test="dname!=null">

dname=#{dname},

</if>

<if test="dloc!=null">

loc=#{dloc}

</if>

</set>

where deptno=#{dno}

</update>

foreach标签

<!-- foreach -->

<!-- 动态 sql foreach in item:定义变量,用于接收遍历出的集合元素,index:索引 collection:集合类型 open/close:迭代出的元素组合的开始/结束符号 separator:元素之间的分隔符 -->

<select id="dynaForeachIn" parameterType="java.util.List"

resultMap="deptMap">

SELECT <include refid="deptColumns" /> FROM dept WHERE deptno IN

<foreach item="item" index="index" collection="list" open="(" separator="," close=")">

#{item}

</foreach>

</select>

<!-- 批量插入 -->

<!-- 动态sql batch insert -->

<insert id="forEachInsert" parameterType="java.util.List">

INSERT INTO dept(DEPTNO,DNAME,LOC) VALUES

<foreach item="item" index="index" collection="list" separator=",">

(#{item.dno},#{item.dname},#{item.dloc})

</foreach>

</insert>

<!-- 批量删除 -->

<!-- 动态sql batch delete -->

<delete id="forEachDelete" parameterType="java.util.List">

DELETE FROM dept WHERE deptno IN

<foreach item="item" index="index" collection="list" open="("

separator="," close=")">

#{item}(9,10,11)

</foreach>

</delete>

转载地址:http://xpazi.baihongyu.com/

你可能感兴趣的文章