目录
????????SqlSessionFactoryBuilder
使用单例模式创建SqlSessionFactory对象????????
????????SqlSessionFactory的openSession()方法
????????SqlSession对象的作用?????????
? ? ? ? 2.1MyBatis核心配置文件中的主要元素
????????db.properties文件实现动态参数配置
????????常见Java类型的默认别名问题?????????
对MyBatis框架已经有了一个初步了解,但是要想熟练地使用MyBatis框架进行实际开发,只会简单的配置是不行的,我们还需要对框架中的核心对象、核心配置文件以及映射文件有更深入的了解。本章将针对MyBatis核心对象、核心配置文件和映射文件进行讲解。
?????????由于build()方法中的参数environment和properties都可以为null,所以SqlSessionFactoryBuilder构建SqlSessionFactory对象的build()方法按照配置信息的传入方式,可以分为三种形式。
?build(InputStream inputStream,String environment,Properties properties)
????????上述build()方法中,参数inputStream是字节流,它封装了XML文件形式的配置信息;参数environment和参数properties为可选参数。其中,参数environment决定将要加载的环境,包括数据源和事务管理器;参数properties决定将要加载的properties文件。
?build(Reader reader,String environment,Properties properties)
由上述build()方法可知,第二种形式的build()方法参数作用与第一种形式大体一致,唯一不同的是,第一种形式的build()方法使用InputStream字节流封装了XML文件形式的配置信息,而第二种形式的build()方法使用Reader字符流封装了xml文件形式的配置信息。?
build(Configuration config)
通过以上代码可知,配置信息可以通过InputStream(字节流)、Reader(字符流)、Configuration(类)三种形式提供给SqlSessionFactoryBuilder的build()方法。
通过过读取XML配置文件的方式构造SqlSessionFactory对象的关键代码如下所示。
// 读取配置文件
InputStream inputStream = Resources.getResourceAsStream("配置文件位置");
// 根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory对象是线程安全的,它一旦被创建,在整个应用程序执行期间都会存在。如果我们多次创建同一个数据库的SqlSessionFactory对象,那么该数据库的资源将很容易被耗尽。通常每一个数据库都只创建一个SqlSessionFactory对象,所以在构建SqlSessionFactory对象时,建议使用单例模式。
????????openSession(ExecutorType execType)参数值
参数execType有三个可选值: ?
ExecutorType.SIMPLE:表示为每条语句创建一条新的预处理语句。 ? ? ? ? ExecutorType.REUSE:表示会复用预处理语句。 ? ? ? ?
ExecutorType.BATCH:表示会批量执行所有更新语句。
???????openSession(ExecutorType ?execType,Boolean ?autoCommit)参数值
参数execType有三个可选值,同openSession(ExecutorType execType)的参数。 ?
参数autoCommit可设置是否开启事务。
?????openSession(ExecutorType ?execType,Connection connection)参数值
参数execType有三个可选值,同openSession(ExecutorType execType)的参数。 ? ? ?
参数connection可提供自定义连接。?
????????? SqlSession是MyBatis框架中另一个重要的对象,它是应用程序与持久层之间执行交互操作的一个单线程对象,主要作用是执行持久化操作,类似于JDBC中的Connection。SqlSession对象包含了执行SQL操作的方法,由于其底层封装了JDBC连接,所以可以直接使用SqlSession对象来执行已映射的SQL语句。
注解:id是唯一标识的一部分,准确来说是namespace.statementId
?每一个线程都应该有一个自己的SqlSession对象,并且该对象不能共享。SqlSession对象是线程不安全的,因此其使用范围最好在一次请求或一个方法中,绝不能将其放在类的静态字段、对象字段或任何类型的管理范围(如Servlet的HttpSession)中使用。SqlSession对象使用完之后,要及时的关闭,SqlSession对象通常放在finally块中关闭
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
// 此处执行持久化操作
} finally { sqlSession.close(); }
????????<configuration>元素是整个XML配置文件的根元素,相当于MyBatis各元素的管理员。<configuration>有很多子元素,MyBatis的核心配置就是通过这些子元素完成的。需要注意的是,在核心配置文件中,<configuration>的子元素必须按照上图由上到下的顺序进行配置,否则MyBatis在解析XML配置文件的时候会报错。
<properties>是一个配置属性的元素,该元素的作用是读取外部文件的配置信息。 假设现在有一个配置文件 db.properties,该文件配置了数据库的连接信息,具体如下:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root
如果想获取数据库的连接信息,可以在 MyBatis 的核心配置文件 mybatis-config.xml 中使用<properties>元素先引入 db.properties 文件,具体代码如下:
<properties resource="db.properties" />
引入 db.properties 文件后,如果希望动态获取 db.properties 文件中的数据库连接信息,可以使用<property>元素配置,示例代码如下:
<dataSource type="POOLED">
<!-- 数据库驱动 -->
<property name="driver" value="${jdbc.driver}" />
<!-- 连接数据库的url -->
<property name="url" value="${jdbc.url}" />
<!-- 连接数据库的用户名 -->
<property name="username" value="${jdbc.username}" />
<!-- 连接数据库的密码 -->
<property name="password" value="${jdbc.password}" />
</dataSource>
?????????完成上述配置后,<dataSource>元素中连接数据库的 4 个属性(driver、url、username 和 password)值将会由db.properties 文件中对应的值来动态替换。这样一来,<properties>元素就可以通过 db.properties 文件实现动态参数配置。
userName命名和数据库中的uname不一致,这时候用<settings>元素处理
<settings>
<!-- 是否开启缓存 -->
<setting name="cacheEnabled" value="true" />
<!-- 是否开启延迟加载,如果开启,所有关联对象都会延迟加载 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 是否开启关联对象属性的延迟加载,如果开启,对任意延迟属性的调用都
会使用带有延迟加载属性的对象向完整加载,否则每种属性都按需加载 -->
<setting name="aggressiveLazyLoading" value="true" />
...
</settings>
处理之前:?
?
处理之后:
<?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>
<!--引入外部db.properties-->
<properties resource="db.properties"></properties>
<settings>
<!--开启 全局缓存,默认true-->
<setting name="cacheEnabled" value="true"/>
<!--开启 全局懒加载,默认是false-->
<setting name="lazyLoadingEnabled" value="true"></setting>
<!--开启 关联属性的懒加载,默认false-->
<setting name="aggressiveLazyLoading" value="true"></setting>
<!--开启 驼峰映射-->
<setting name="mapUnderscoreToCamelCase" value="true"></setting>
</settings>
<!--配置连接使用的相关参数
default为默认使用的环境:development 测试环境
product 生产环境
-->
<environments default="development">
<!--测试环境-->
<environment id="development">
<!--事务管理类型:指定事务管理的方式 JDBC-->
<transactionManager type="JDBC"/>
<!--数据库连接相关配置,动态获取config.properties文件里的内容-->
<!--数据源类型:POOLED 表示支持JDBC数据源连接池
UNPOOLED 表示不支持数据源连接池
JNDI 表示支持外部数据源连接池
-->
<dataSource type="POOLED">
<!--此处使用的是MySQL数据库,使用Oracle数据库时需要修改,仔细检查各项参数是否正确,里面配置了时区、编码方式、SSL,用以防止中文查询乱码,导致查询结果为null及SSL警告等问题-->
<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>
<!--配置xxxMapper.xml文件的位置-->
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
User类中的? userName -->对应列名 user_name(搞带下划线保证他俩变成驼峰式后相同)?
????????????????核心配置文件若要引用一个POJO实体类,需要输入POJO实体类的全限定类名,而全限定类名比较冗长,如果直接输入,很容易拼写错误。例如,POJO实体类User的全限定类名是com.itheima.pojo.User,未设置别名之前,映射文件的select语句块若要引用POJO类User,必须使用其全限定类名,引用代码如下。
<select id="findById" parameterType="int" resultType="com.itheima.pojo.User">
select * from users where uid = #{id}
</select>
????????方式一:在<typeAliases>元素下,使用多个<typeAlias>元素为每一个全限定类逐个配置别名。
<typeAliases>
<typeAlias alias=“Usertype="com.itheima.pojo.User"/>
<typeAlias alias="Student" type="com.itheima.pojo.Student"/>
<typeAlias alias="Employee" type="com.itheima.pojo.Employee"/>
<typeAlias alias="Animal" type="com.itheima.pojo.Animal"/>
</typeAliases>
????????方式二:通过自动扫描包的形式自定义别名。
<typeAliases>
<package name="com.itheima.pojo"/>
</typeAliases>
<typeAliases>
<!-- 第一种配置方式 -->
<typeAlias type="com.it.pojo.User" alias="user"></typeAlias>
<!-- 第二种配置方式 默认实体的类名就是别名,大小写不区分-->
<package name="com.it.pojo"></package>
</typeAliases>
? ???????????除了可以使用<typeAliases>元素为实体类自定义别名外,MyBatis框架还为许多常见的Java类型(如数值、字符串、日期和集合等)提供了相应的默认别名。例如别名_byte映射类型byte、_long映射类型long等,别名可以在MyBatis中直接使用,但由于别名不区分大小写,所以在使用时要注意重复定义的覆盖问题。?
<select id="findTotal"
resultType="int"
>
select count(*) from users
</select>
这里的int是MyBatis对于我们默认的常用的数据类型做了默认int?
测试
package com.it.test;
import com.it.pojo.User;
import jdk.management.resource.ResourceRequest;
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.InputStream;
public class UserTest01 {
@Test
public void findById() throws Exception
{
//1.获取核心配置文件
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
//2.创建sqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
//3.创建sqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
//4.执行sql语句 sql语句唯一标识:namespace.statementId
User user=sqlSession.selectOne("com.it.pojo.User.findById",1);
System.out.println(user);
//5.释放资源
sqlSession.close();
}
@Test
public void findTotal() throws Exception
{
//1.获取核心配置文件
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
//2.创建sqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
//3.创建sqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
//4.执行sql语句 sql语句唯一标识:namespace.statementId
Integer total=sqlSession.selectOne("com.it.pojo.User.findTotal");
System.out.println("数据的总数量:"+total);
//5.释放资源
sqlSession.close();
}
}
?
????????????????MyBatis可以配置多套运行环境,如开发环境、测试环境、生产环境等,我们可以灵活选择不同的配置,从而将SQL映射到不同运行环境的数据库中。不同的运行环境可以通过<environments>元素来配置,但不管增加几套运行环境,都必须要明确选择出当前要用的唯一的一个运行环境。
????????????????MyBatis的运行环境信息包括事务管理器和数据源。在MyBatis的核心配置文件中,MyBatis通过<environments>元素定义一个运行环境。<environment>元素有两个子元素,<transactionManager>元素和<daraSource>元素。<transactionManager>元素用于配置运行环境的事务管理器;<daraSource>元素用于配置运行环境的数据源信息。
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" /><!—设置使用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>
?????????????????在MyBatis中,<transcationManager>元素可以配置两种类型的事务管理器,分别是JDBC和MANAGED。 ? ? ?
????????????????JDBC:此配置直接使用JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务的作用域。 ? ? ?
????????????????MANAGED:此配置不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。默认情况下,它会关闭连接,但可以将<transcationManager>元素的closeConnection属性设置为false来阻止它默认的关闭行为。
?????????MyBatis数据源类型
???????????????项目中使用Spring+MyBatis,则没必要在MyBatis中配置事务管理器,实际开发中,项目会使用Spring自带的管理器来实现事务管理。对于数据源的配置,MyBatis提供了UNPOOLED、POOLED和JNDI三种数据源类型。
????????UNPOOLED数据源
????????????????UNPOOLED表示数据源为无连接池类型。配置此数据源类型后,程序在每次被请求时会打开和关闭数据库连接。UNPOOLED适用于对性能要求不高的简单应用程。UNPOOLED类型的数据源需要配置5种属性。
???????UNPOOLED数据源需要配置的属性
????????POOLED数据源
????????????????POOLED表示数据源为连接池类型。POOLED数据源利用“池”的概念将JDBC连接对象组织起来,节省了在创建新的连接对象时需要初始化和认证的时间。POOLED数据源使得并发Web应用可以快速的响应请求,是当前比较流行的数据源配置类型。
????????POOLED数据源可额外配置的属性
????????JNDI数据源
????????JNDI 表示数据源可以在 EJB 或应用服务器等容器中使用。JNDI数据源需要配置的属性如下所示。
<environments default="development">
<!--测试环境-->
<environment id="development">
<!--事务管理类型:指定事务管理的方式 JDBC-->
<transactionManager type="JDBC"/>
<!--数据库连接相关配置,动态获取config.properties文件里的内容-->
<!--数据源类型:POOLED 表示支持JDBC数据源连接池
UNPOOLED 表示不支持数据源连接池
JNDI 表示支持外部数据源连接池
-->
<dataSource type="POOLED">
<!--此处使用的是MySQL数据库,使用Oracle数据库时需要修改,仔细检查各项参数是否正确,里面配置了时区、编码方式、SSL,用以防止中文查询乱码,导致查询结果为null及SSL警告等问题-->
<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>
<environment id="test">
<!--事务管理类型:指定事务管理的方式 JDBC-->
<transactionManager type="JDBC"/>
<!--数据库连接相关配置,动态获取config.properties文件里的内容-->
<!--数据源类型:POOLED 表示支持JDBC数据源连接池
UNPOOLED 表示不支持数据源连接池
JNDI 表示支持外部数据源连接池
-->
<dataSource type="POOLED">
<!--此处使用的是MySQL数据库,使用Oracle数据库时需要修改,仔细检查各项参数是否正确,里面配置了时区、编码方式、SSL,用以防止中文查询乱码,导致查询结果为null及SSL警告等问题-->
<property name="driver" value="${mysql.driver}"/>
<property name="url"
value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
这里虽然default默认使用的配置是development,但是通过build()方法中第二个位置的参数指定使用"test"配置
因为"test"配置我输的密码是123456错的,运行会报密码错误
?????????? 在MyBatis的核心配置文件中,<mappers>元素用于引入MyBatis映射文件。映射文件包含了POJO对象和数据表之间的映射信息,MyBatis通过核心配置文件中的<mappers>元素找到映射文件并解析其中的映射信息。通过<mappers>元素引入映射文件的方法有4种。
????????a.使用类路径引入
<mappers>
<mapper resource="com/itheima/mapper/UserMapper.xml"/>
</mappers>
????????b.使用本地文件路径引入
<mappers>
<mapper url="file:///D:/com/itheima/mapper/UserMapper.xml"/>
</mappers>
????????c.使用接口类引入
<mappers>
<mapper class="com.itheima.mapper.UserMapper"/>
</mappers>
????????d.使用包名引入
<mappers>
<package name="com.itheima.mapper"/>
</mappers>
?
UserMapperTest
package com.it.mapper;
import com.it.pojo.User;
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.Before;
import org.junit.Test;
import java.io.InputStream;
import static org.junit.Assert.*;
public class UserMapperTest {
UserMapper userMapper=null;
SqlSession sqlSession=null;
@Before
public void setUp() throws Exception {
//1.获取核心配置文件
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
//2.创建sqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
//3.创建sqlSession对象
sqlSession=sqlSessionFactory.openSession();
//获取接口的动态代理对象
//执行方法时,要找哪一条sql语句来执行? sql的唯一标识是由namespace.statementId
userMapper=sqlSession.getMapper(UserMapper.class);
}
@Test
public void findById() {
User user=userMapper.findById(1);
System.out.println(user);
sqlSession.close();
}
@Test
public void findTotal() {
Integer total=userMapper.findTotal();
System.out.println(total);
sqlSession.close();
}
}
UserMapper
package com.it.mapper;
import com.it.pojo.User;
/*
接口式开发:
1.方法的名称需要保证和映射文件中的sql语句的statementId一致
2.namespace的值必须是接口的全路径
*/
public interface UserMapper {
public User findById(int id);
public Integer findTotal();
}
? ? ??1. 用于区分不同的mapper,全局唯一。
? ? ? 2.??绑定DAO接口,即面向接口编程。当namespace绑定某一接口之后,可以不用写该接口的实现类,MyBatis会通过接口的全限定名查找到对应的mapper配置来执行SQL语句,因此namespace的命名必须跟接口同名。
??????????在不同的映射文件中,<mapper>元素的子元素的id可以相同,MyBatis通过<mapper>元素的namespace属性值和子元素的id联合区分不同的Mapper.xml文件。接口中的方法与映射文件中SQL语句id应一一对应。
????????<select>元素用来映射查询语句,它可以从数据库中查询数据并返回。使用<select>元素执行查询操作非常简单,示例代码如下:
<!—查询操作 -->
<select id="findUserById" parameterType="Integer"
resultType="com.itheima.pojo.User">
select * from users where id = #{id}
</select>
??????????<insert>元素用于映射插入语句,在执行完<insert>元素中定义的SQL语句后,会返回插入记录的数量。使用< insert >元素执行插入操作非常简单,示例代码如下:
<!—插入操作 --><insert id="addUser" parameterType="com.itheima.pojo.User">
insert into users(uid,uname,uage)values(#{uid},#{uname},#{uage})
</insert>
<insert id="addUser"
parameterType="user"
>
INSERT into users(uid,uname,uage) values(#{uid},#{uname},#{uage});
</insert>
@Test
public void addUser()
{
User user=new User();
user.setUage(20);
user.setUid(3);
user.setUname("面壁者罗辑");
userMapper.addUser(user);
//手动提交事务
sqlSession.commit();
sqlSession.close();
}
???????????很多时候,执行插入操作后,需要获取插入成功的数据生成的主键值,不同类型数据库获取主键值的方式不同,下面分别对支持主键自动增长的数据库获取主键值和不支持主键自动增长的数据库获取主键值的方式进行介绍。
????????? 如果使用的数据库支持主键自动增长(如MySQL和SQL Server),那么可以通过keyProperty属性指定POJO类的某个属性接收主键返回值(通常会设置到id属性上),然后将useGeneratedKeys的属性值设置为true。
<insert id="addUser" parameterType="com.itheima.pojo.User"
keyProperty="uid" useGeneratedKeys="true" >
insert into users(uid,uname,uage)values(#{uid},#{uname},#{uage})
</insert>
uid直接插入的时候写null?
<insert id="addUser"
parameterType="user"
useGeneratedKeys="true"
keyProperty="uid"
>
INSERT into users(uid,uname,uage) values(null,#{uname},#{uage});
</insert>
@Test
public void addUser()
{
User user=new User();
user.setUage(20);
// user.setUid(3);
user.setUname("面壁者罗辑");
System.out.println("插入数据之前的用户id:"+user.getUid());
userMapper.addUser(user);
System.out.println("插入数据之后的用户id:"+user.getUid());
//手动提交事务
sqlSession.commit();
sqlSession.close();
}
<!--
第一种方式:支持主键自增 SELECT LAST_INSERT_ID()
第二种方式:不支持主键自增
-->
<insert id="addUser"
parameterType="user"
>
<selectKey keyProperty="uid"
resultType="Integer"
order="AFTER"
>
SELECT LAST_INSERT_ID()
</selectKey>
INSERT into users(uid,uname,uage) values(null,#{uname},#{uage});
</insert>
???????使用MyBatis提供的<selectKey>元素来自定义主键。
<selectKey
keyProperty="id” resultType="Integer"
order="BEFORE” statementType="PREPARED">
????????在上述<selectKey>元素的属性中,order属性可以被设置为BEFORE或AFTER。如果设置为BEFORE,那么它会首先执行<selectKey>元素中的配置来设置主键,然后执行插入语句;如果设置为AFTER,那么它先执行插入语句,然后执行<selectKey>元素中的配置内容。
AFTER改成BEFORE?,null改成#{uid}
<!--
第一种方式:支持主键自增 SELECT LAST_INSERT_ID()
第二种方式:不支持主键自增
-->
<insert id="addUser"
parameterType="user"
>
<selectKey keyProperty="uid"
resultType="Integer"
order="BEFORE"
>
SELECT FLOOR(RAND()*1000+1)
</selectKey>
INSERT into users(uid,uname,uage) values(#{uid},#{uname},#{uage});
</insert>
@Test
public void addUser()
{
User user=new User();
user.setUage(20);
// user.setUid(3);
user.setUname("面壁者罗辑");
System.out.println("插入数据之前的用户id:"+user.getUid());
userMapper.addUser(user);
System.out.println("插入数据之后的用户id:"+user.getUid());
//手动提交事务
sqlSession.commit();
sqlSession.close();
}
????????<update>元素用于映射更新语句,它可以更新数据库中的数据。在执行完元素中定义的SQL语句后,会返回更新的记录数量。使用<update>元素执行更新操作非常简单,示例代码如下:
<!—更新操作 -->
<update id="updateUser" parameterType="com.itheima.pojo.User">
update users set uname= #{uname},uage = #{uage} where uid = #{uid} </update>
@Test
public void updateUser()
{
User user=new User();
user.setUname("王五");
user.setUage(25);
user.setUid(3);
userMapper.updateUser(user);
sqlSession.commit();
sqlSession.close();
}
<update id="updateUser"
parameterType="user"
>
UPDATE users set uname=#{uname},uage=#{uage} where uid=#{uid}
</update>
????????<delete>元素用于映射删除语句,在执行完<delete>元素中的SQL语句之后,会返回删除的记录数量。使用<delete>元素执行删除操作非常简单,示例代码如下所示:????????
<!-- 删除操作 -->
<delete id="deleteUser" parameterType="Integer">
delete from users where uid=#{uid}
</delete>
????????<delete>元素中,除了上述示例代码中的几个属性外,还有其他一些可以配置的属性,如flushCache、timeout等。
<delete id="deleteUser"
parameterType="Integer">
DELETE FROM users where uid=#{uid}
</delete>
@Test
public void deleteUser()
{
userMapper.deleteUser(3);
sqlSession.commit();
sqlSession.close();
}
? ????????在一个映射文件中,通常需要定义多条SQL语句,这些SQL语句的组成可能有一部分是相同的(如多条select语句中都查询相同的id、username字段),如果每一个SQL语句都重写一遍相同的部分,势必会增加代码量。针对此问题,可以在映射文件中使用MyBatis所提供的<sql>元素,将这些SQL语句中相同的组成部分抽取出来,然后在需要的地方引用。 ? ? ? ????????? <sql>元素的作用是定义可重用的SQL代码片段,它可以被包含在其他语句中。<sql>元素可以被静态地(在加载参数时)参数化,<sql>元素不同的属性值通过包含的对象发生变化。
<!--定义要查询的表 -->
<sql id=“someinclude">from <include refid="${include_target}" /></sql>
<!--定义查询列 --><sql id=“userColumns"> uid,uname,uage </sql>
<!--根据客户id查询客户信息 -->
<select id="findUserById" parameterType="Integer"
resultType="com.itheima.pojo.User"> select
<include refid="userColumns"/>
<include refid="someinclude">
<property name="include_target" value="users" /></include>
where uid = #{uid}
</select>
<sql id="users">users</sql>
<sql id="someinclude"
>
from <include refid="${include_target}"></include>
</sql>
<sql id="userColumns">
uid,uname,uage
</sql>
<select id="findById"
parameterType="int"
resultType="user">
select <include refid="userColumns"></include>
<include refid="someinclude">
<property name="include_target" value="users"/>
</include>
where uid=#{id}
</select>
运行 findById:?
?????????<resultMap>元素表示结果映射集,是MyBatis中最重要也是功能最强大的元素。<resultMap>元素主要作用是定义映射规则、更新级联以及定义类型转化器等。 ? ?????????????
????????数据表中的列和需要返回的对象的属性可能不会完全一致,这种情况下MyBatis不会自动赋值,这时就需要使用<resultMap>元素进行结果集映射。
USE mybatis;
CREATE TABLE t_student(
sid INT PRIMARY KEY AUTO_INCREMENT,
sname VARCHAR(50),
sage INT
);
INSERT INTO t_student(sname,sage) VALUES('Lucy',25);
INSERT INTO t_student(sname,sage) VALUES('Lili',20);
INSERT INTO t_student(sname,sage) VALUES('Jim',20);
package com.itheima.pojo;
public class Student {
private Integer id; // 主键id
private String name; // 学生姓名
private Integer age; // 学生年龄
// 省略getter/setter方法
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";}
}
<!-- 只显示mapper元素的内容-->
<mapper namespace="com.itheima.mapper.StudentMapper">
<resultMap type="com.itheima.pojo.Student" id="studentMap">
<id property="id" column="sid"/><result property="name" column="sname"/><result property="age" column="sage"/>
</resultMap>
<select id="findAllStudent" resultMap="studentMap">
select * from t_student</select>
</mapper>
<mapper resource="com/itheima/mapper/StudentMapper.xml">
<mapper>
public class MyBatisTest {
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
// init()方法省略
@Test
public void findAllStudentTest() {
List<Student> list = sqlSession.selectList("com.itheima.mapper.StudentMapper.
findAllStudent");
for (Student student : list) { System.out.println(student);}}
// destory()方法省略
}
MyBatisTest.java
package com.it.test;
import com.it.pojo.Student;
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.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.List;
public class MyBatisTest {
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
@Before
public void init()
{
try {
//1.获取核心配置文件
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
//2.创建sqlSessionFactory工厂对象
sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
sqlSession=sqlSessionFactory.openSession();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void findAllStudentTest()
{
List<Student> studentList=sqlSession.selectList("com.it.mapper.StudentMapper.findAllStudent");
for (Student s:studentList)
{
System.out.println(s);
}
}
@After
public void destory()
{
sqlSession.commit();
sqlSession.close();
}
}
StudentMapper.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为映射的根节点,用来管理DAO接口
namespace指定DAO接口的完整类名,表示mapper配置文件管理哪个DAO接口(包.接口名)
mybatis会依据这个接口动态创建一个实现类去实现这个接口,而这个实现类是一个Mapper对象
-->
<mapper namespace="com.it.mapper.StudentMapper">
<!--
id = "接口中的方法名"
parameterType = "接口中传入方法的参数类型"
resultType = "返回实体类对象:包.类名" 处理结果集 自动封装
注意:sql语句后不要出现";"号
查询:select标签
增加:insert标签
修改:update标签
删除:delete标签
-->
<resultMap id="studentMap" type="student">
<id column="sid" property="id"></id>
<result column="sname" property="name"></result>
<result column="sage" property="age"></result>
</resultMap>
<select id="findAllStudent"
resultMap="studentMap"
>
select * from t_student
</select>
</mapper>
? ? Student.java? ??
package com.it.pojo;
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
????????在上述案例中,由于每个方法执行时都需要读取配置文件,并根据配置文件的信息构建SqlSessionFactory对象、创建SqlSession对象、释放资源,这导致了大量的重复代码。为了简化开发,我们可以将读取配置文件和释放资源的代码封装到一个工具类中,然后通过工具类创建SqlSession对象。
package com.it.utils;
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;
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory=null;
static {
//创建sqlSessionFactory
try {
//1.获取核心配置文件
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
//2.创建sqlSessionFactory工厂对象
sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSession()
{
return sqlSessionFactory.openSession();
}
}
当我们需要sqlSession时直接掉MyBatisUtils.getSession()即可
? ? ? ? 要求:完成一个员工管理系统,能够实现如下功能根据id查询、新增、修改、删除员工信息
????????员工表详情?
????????现有一张员工表如下。利用本章所学知识完成一个员工管理系统。实现如下功能:根据id查询员工信息、新增员工信息、根据id修改员工信息、根据id删除员工信息。
use mybatis;
create table employee(
id int primary key auto_increment,
name varchar(20) not null,
age int not null,
position varchar(20) );
insert into employee(id,name,age,position) values(null,'张三',20,'员工'),
(null,'李四',18, '员工'),(null,'王五',35,'经理');
? ? ? ? 项目搭建:创建建一个名称为mybatisdemo的项目,并在项目中引入 MySQL 驱动包、 JUnit 测试包、MyBatis 的核心包等相关依赖、创建数据库连接信息配置文件、创建 MyBatis 的核心配置文件。核心配置文件的内容如下。
<configuration><properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<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>
</configuration>
????????jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
jdbc.username=root
jdbc.password=root
? ? ? ? mybatis-config.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" >
<!--配置mybatis环境-->
<configuration>
<!--引入外部 properties-->
<properties resource="jdbc.properties"></properties>
<!--别名映射-->
<typeAliases >
<package name="com.it.pojo"/>
</typeAliases>
<!--配置连接使用的相关参数
default为默认使用的环境:development 测试环境
product 生产环境
-->
<environments default="development">
<!--测试环境-->
<environment id="development">
<!--事务管理类型:指定事务管理的方式 JDBC-->
<transactionManager type="JDBC"/>
<!--数据库连接相关配置,动态获取config.properties文件里的内容-->
<!--数据源类型:POOLED 表示支持JDBC数据源连接池
UNPOOLED 表示不支持数据源连接池
JNDI 表示支持外部数据源连接池
-->
<dataSource type="POOLED">
<!--此处使用的是MySQL数据库,使用Oracle数据库时需要修改,仔细检查各项参数是否正确,里面配置了时区、编码方式、SSL,用以防止中文查询乱码,导致查询结果为null及SSL警告等问题-->
<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>
<mappers>
<!--下面编写mapper映射文件↓↓↓↓↓ 参考格式:<mapper resource="dao/UserMapper.xml"/> -->
<mapper resource="com/it/mapper/EmployeeMapper.xml"></mapper>
</mappers>
</configuration>
? ? ? ? EmployeeMapper.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为映射的根节点,用来管理DAO接口
namespace指定DAO接口的完整类名,表示mapper配置文件管理哪个DAO接口(包.接口名)
mybatis会依据这个接口动态创建一个实现类去实现这个接口,而这个实现类是一个Mapper对象
-->
<mapper namespace="com.it.mapper.EmployeeMapper">
<!--
id = "接口中的方法名"
parameterType = "接口中传入方法的参数类型"
resultType = "返回实体类对象:包.类名" 处理结果集 自动封装
注意:sql语句后不要出现";"号
查询:select标签
增加:insert标签
修改:update标签
删除:delete标签
-->
<select id="findEmployeeById"
parameterType="Integer"
resultType="employee"
>
SELECT * FROM employee WHERE id=#{id};
</select>
<insert id="save"
parameterType="employee"
>
INSERT INTO employee values(null,#{name},#{age},#{position});
</insert>
<update id="updateEmployeeById"
parameterType="employee"
>
UPDATE employee set name=#{name},age=#{age},position=#{position} where id=#{id}
</update>
<delete id="deleteEmployeeById"
parameterType="Integer"
>
DELETE FROM employee where id=#{id}
</delete>
</mapper>
? ? ? ? Employee
package com.it.pojo;
public class Employee {
private int id;
private String name;
private String position;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", position='" + position + '\'' +
", age=" + age +
'}';
}
}
? ? ? ? MyBatisUtils
package com.it.utils;
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;
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory=null;
static {
//创建sqlSessionFactory
try {
//1.获取核心配置文件
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
//2.创建sqlSessionFactory工厂对象
sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSession()
{
return sqlSessionFactory.openSession();
}
}
? ? ? ? pom.xml
<?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>org.example</groupId>
<artifactId>mybatiesdemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
? ? ? ? ? ? ? ?MyBatisTest
?
package com.it.test;
import com.it.pojo.Employee;
import com.it.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class MyBatisTest {
@Test
public void findByIdTest()
{
//获取sqlSession
SqlSession sqlSession =MyBatisUtils.getSession();
//执行sql
Employee employee= sqlSession.selectOne("com.it.mapper.EmployeeMapper.findEmployeeById",1);
System.out.println(employee);
sqlSession.commit();
sqlSession.close();
}
@Test
public void saveTest()
{
Employee employee=new Employee();
employee.setId(1);
employee.setAge(50);
employee.setName("赵六");
employee.setPosition("经理");
//获取sqlSession
SqlSession sqlSession =MyBatisUtils.getSession();
//执行sql
sqlSession.update("com.it.mapper.EmployeeMapper.save",employee);
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateEmployeeByIdTest()
{
Employee employee=new Employee();
employee.setId(4);
employee.setAge(60);
employee.setName("赵六六");
employee.setPosition("普通员工");
//获取sqlSession
SqlSession sqlSession =MyBatisUtils.getSession();
//执行sql
sqlSession.update("com.it.mapper.EmployeeMapper.updateEmployeeById",employee);
sqlSession.commit();
sqlSession.close();
}
@Test
public void deleteEmployeeByIdTest()
{
//获取sqlSession
SqlSession sqlSession =MyBatisUtils.getSession();
//执行sql
sqlSession.update("com.it.mapper.EmployeeMapper.deleteEmployeeById",4);
sqlSession.commit();
sqlSession.close();
}
}
?运行结果(仅findByIdTest())
? ? ? ? ? ? ?总结
- ?????????这个Id后面不要空格!
- 这里路径用/
- 这个后面别忘记带参数1