mybatis基础
一.MyBatis零基础入门
1.mybatis课程介绍
2.mybatis特性
3.和其它持久层技术对比
4.Mybatis的下载
MyBatis下载地址:https://github.com/mybatis/mybatis-3
二.搭建MyBatis
1.创建maven工程
(1) 创建maven父工程
- 第一步选中maven工程创建
- 输入你的ArtifactId和groupId(项目唯一标识符,坐标)
- 点击finish,Maven父工程创建成功
- 设置项目Maven,点击Maven右边的小扳手就可以打开设置Maven仓库和setting配置文件,Maven下载依赖的时候先去寻找本地仓库有没有,没有再去自己setting配置中的镜像网站下载,没配置直接中央仓库下载,配置好点击apply
- 创建子工程(在这里面编写自己的模块功能)
- 配置打包方式,packaging为jar包表明是一个jar工程
- 导入依赖
<dependencies>
<!-- Mybatis核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
父工程的最要作用就是管理子工程jar依赖的版本问题,在父工程导入的依赖,在子工程中使用就不需要在编写版本号。
2.创建MyBatis的核心配置文件
习惯上命名为mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。将来整合Spring之后,这个配置文件可以省略,所以大家操作可以直接复制,粘贴。
核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息
核心配置文件存放的位置是src/main/resources目录下
- 创建一个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="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
</configuration>
3.创建Mapper接口
MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类
- 数据库student表和实体类
- Mapper接口创建
4.创建MyBatis的映射文件
相关概念:ORM(Object Relationship Mapping)对象关系映射
- 对象:java的实体类对象
- 关系:关系型数据库
- 映射:二者之间的对应关系
1.映射文件的命名规则
表所对应的实体类的类名+Mapper.xml
列如:表t_user,映射的实体类为User,所对应的接口UserMapper,对应的映射文件名为UserMapper.xml
因此一个映射文件对应一个实体类,对应一张表的操作
MyBatis映射文件用于编写SQL,访问以及操作表中的数据
2.MyBatis映射文件存放的位置是src/main/resources/mappers目录下 mapper接口中的全类名和映射文件的命名空间(namespace)保持一致
mapper接口中的方法的方法名和映射文件中编写SQL的标签的id属性保持一致
3.MyBatis面向接口的两个一致和对应关系 MyBatis面向接口的两个一致
* 1.映射文件的namespace要和mapper接口的全类名一致
* 2.映射文件中SQL语句的id要和mapper接口中的方法名一致
*
* 对应关系
* 表–实体类–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="com.cn.cslg.mybatis.mapper.UserMapper">
<!-- sql语句方法写入 int insertUser(); -->
<insert id="insertUser">
insert into t_user values (null,'admin','123456',23,'男','123.@qq.com')
</insert>
</mapper>
Mapper核心配置文件引入Mapper映射文件
<!--引入映射文件-->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
5.通过juint测试功能
SqlSession:代表Java程序和数据库之间的会话,(HTTPSession是Java程序和浏览器之间的会话)
SqlSessionFactory:是“生产”SqlSession的“工厂”
工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们可以把创建这个对象的相关代码封装到一个“工厂类”中,以后使用这个工厂类来“生产”我们需要的对象
package com.cn.cslg.mybatis.test;
import com.cn.cslg.mybatis.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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisTest {
/**
* SqlSession默认不自动提交事务,若需要自动提交事务
* 可以使用sqlSessionFactoryp。open(true)
*
*/
@Test
public void testMyBatisInsertUser() throws IOException {
//1.加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//2.获取SqlSessionFactoryBuilder,是SqlSession工厂对象的构建对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//3.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);
//4.获取SqlSession,是java和数据库之间的会话,就像httpSession是浏览器和java之间的会话,设置为true开启自动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取mapper接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//测试功能
mapper.insertUser();
//提交事务
// sqlSession.commit();
}
}
6.加入log4j日志功能
- 加入依赖
<!-- log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- 加入log4j的配置文件
log4j的配置文件名为log4j.xml,存放的位置为src/main/resources目录下
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!-- 命名空间爆红没有关系,不影响使用,下面的level标签中是指的输出范围 -->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
日志的级别
FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
从左到右打印的内容越来越详细
三.核心配置文件详解
核心配置文件中的标签必须按照固定的顺序
properties、settings、typeAliases、typeHandlers、objectFactory、objectWrapperFactory、reflectorFactory、plugins、environments、databaseIdProvider、mappers
<?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:设置默认使用的环境的id
-->
<environments default="development">
<!--
environment:配置某个具体的环境
属性:
id:表示连接数据库的环境的唯一标识,不能重复
-->
<environment id="development">
<!--
transactionManager:设置事务管理方式
属性:
type="JDBC|MANAGED"
JDBC:表示当前环境中,执行SQL时,使用的事JDBC中原生的事务管理方式,事物的提交和回滚需要手动操作
MANAGED:别管理,列如Spring
-->
<transactionManager type="JDBC"/>
<!--
dataSource:配置数据源的类型
type="POOLED|UNPOOLED|NDI"
POOLED:表示使用数据库连接池缓存数据库链接
UNPOOLED:表示不适用竖亥句酷连接池
JNDI:表示使用上下稳重的数据源
-->
<dataSource type="POOLED">
<!-- 设置链接数据库的驱动 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!-- 设置链接数据库的链接地址 -->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<!-- 设置链接数据库的用户名 -->
<property name="username" value="root"/>
<!-- 设置链接数据库的密码 -->
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
</configuration>
TypeAliases标签
typeAliases用来设置类名的别名,通常使用typeAliases下面的package标签设置一整个实体类的包的别名,在Mybatis核心文件中的配置
<!--
typeAlias:设置某个类型的别名
属性:
type:设置需要设置别名的类型
alias:设置某个类型的别名,若不设置该属性,那么该类型拥有默认的别名,即类名不区分大小写
-->
<typeAliases>
<typeAlias type="com.cn.cslg.mybatis.pojo.User" alias="User"></typeAlias>
<!-- 以包为单位,将包下所有的类型设置默认的类型别名, 且类名不区分大小写 -->
<package name="com.cn.cslg.mybatis.pojo"/>
</typeAliases>
在Mapper映射文件中的使用类名的别名,resultType中的User的首字母大小写不用区分
<select id="selectAllUser" resultType="User">
select * from t_user
</select>
<select id="selectAllUser" resultType="user">
select * from t_user
</select>
Package标签映入多个映射文件
包的方式映入Mapper映射文件,解决了配置多个包的问题,其中需要注意在resourc文件夹下面创建多个目录需要用‘/’分割而不是用’.'分隔。
1.首先必须mapper接口所在的包要和映射文件所在的包一致
2. mapper接口要和映射文件的名字一致
<mappers>
<!-- <mapper resource="mappers/UserMapper.xml"/>-->
<!--
已包为单位映入映射文件
要求:
1.mapper接口所在的包要和映射文件所在的包一致
2.mapper接口要和映射文件的名字一致
-->
<package name="com.cn.cslg.mybatis.mapper"/>
</mappers>
四.MyBatis的增删改查
- 添加
<insert id="insertUser">
insert into t_user values (null ,'admin','123456',23,'男','123.@qq.com')
</insert>
- 删除
<delete id="deleteUser">
delete from t_user where id ='3'
</delete>
- 修改
<update id="updateUser">
update t_user set username = 'zkkk' where id=1
</update>
- 查询实体类对象
查询实体类的对象需要设置resultType为实体类返回值,可以通过TypeAliases在MyBatis核心配置文件中通过TypeAliases标签来更改类的别名
<!-- User selectUser();-->
<!--
查询功能的标签必须设置resultType或者resultMap
resultType:设置默认的映射关系
resultMap:设置自定义的映射关系
-->
<select id="selectUser" resultType="com.cn.cslg.mybatis.pojo.User">
select * from t_user where id = 1
</select>
- 查询多个实体类对象
通过更改类的别名来,在resultType中简单的命名,因为通过package标签进行多个映射文件导入,所以别名即为实体类的类名不用区分大小写!
<mappers>
<!-- <mapper resource="mappers/UserMapper.xml"/>-->
<!--
已包为单位引入映射文件
要求:
1.mapper接口所在的包要和映射文件所在的包一致
2.mapper接口要和映射文件的名字一致
-->
<package name="com.cn.cslg.mybatis.mapper"/>
</mappers>
<!-- List<User> selectAllUser();-->
<select id="selectAllUser" resultType="User">
select * from t_user
</select>
注意:
1.查询的标签select必须设置属性resultType或resultMap ,用于设置实体类和数据库的映射关系resultType:自动映射,用于属性名和标准字段名一致的情况
resultMap:自定义映射,用于一对多或多对一字段名和属性名不一致的情况
2.当查询的数据为多条时,不能使用实体类作为返回值,只能使用集合,否则会抛出异常TooManyResultsException;但是若查询的数据只有一条,可以使用实体类或集合为返回值
五.MyBatis获取参数值的两种方式(重点)
MyBatis获取参数值的两种方式:${}和#{} ${}本质字符串拼接,拼接的值为字
符串类型或者日期类型,需要注意单引号问题
#{}本质占位符赋值
MyBatis获取参数值的各种情况
- mapper接口方法的参数为单个字面量类型
- 可以通过KaTeX parse error: Expected 'EOF', got '#' at position 4: {}和#̲{}以任意的名称获取,最好是见…{}的单引号问题
<!--User getUserByUserName(String UserName);-->
<select id="getUserByUserName" resultType="User">
<!--select * from t_user where username = #{UserName}-->
<!-- 注意单引号-->
select * from t_user where username = '${UserName}'
</select>
2.mapper接口方法的参数为多个时
此时MyBatis会将这些参数放在map集合中,以两种方式进行存储
- a>以arg0,arg1…为键,以参数为值
- b>以param1,param2…为键,以参数为值
- 因此只需要通过#{}或者$ {}以键的方式访问值即可,注意${}的引号问题,l例子#{arg0}
<!--User checkLogin(String username,String password);-->
<select id="checkLogin" resultType="User">
<!-- select * from t_user where username=#{arg0} and password=#{arg1}-->
select * from t_user where username=#{param1} and password=#{param2}
</select>
- 若mapper接口方法的参数有多个时,可以手动将这些参数放在mapper中存储
因此只需要通过#{}或者 以键的方式访问值即可,注意 {}以键的方式访问值即可,注意 以键的方式访问值即可,注意{}的引号问题,l例子#{username}
public void testGetAllUser(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
//传输多个参数为mapper集合的时候判断登录
Map<String,Object> map = new HashMap<>();
map.put("username","zkkk");
map.put("password","123456");
User user = mapper.checkLoginByMap(map);
System.out.println(user);
}
<!--User checkLoginByMap(Map<String,Object>map);-->
<select id="checkLoginByMap" resultType="User">
select * from t_user where username=#{username} and password=#{password}
</select>
- 如果mapper接口方法的参数是实体类类型的参数(重点)
因此只需要通过#{}或者 以属性的方式访问值即可,注意 {}以属性的方式访问值即可,注意 以属性的方式访问值即可,注意{}的引号问题,l例子#{类中的属性}
package com.cn.cslg.mybatis.pojo;
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private String sex;
private String email;
....
}
<!--int insertUser(User user);-->
<insert id="insertUser">
insert into t_user values(null ,#{username},#{password},#{age},#{sex},#{email})
</insert>
public void insertUser(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
User user =new User(null,"Lisi","123456",12,"男","123456");
int a = mapper.insertUser(user);
System.out.println(a);
}
- 使用@Param注解(最常用的方式,除了第三种情况以外,其他情况都可以用它)
此时MyBatis会将这些参数放在一个map集合之中,以两种方式进行存储 a>@Param注解的值为键,以参数为值
b>以param1,param2…为键,以参数位置 因此只需要通过#{}和 以键的方式访问值即可,但是需要注意 {}以键的方式访问值即可,但是需要注意 以键的方式访问值即可,但是需要注意{}的单引号问题
public void testCheckLoginByParam(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
User user = mapper.checkLoginByParam("zkkk", "123456");
System.out.println(user);
}
/**
* mapper接口
* 验证登录(使用@param注解)
*/
User checkLoginByParam(@Param("username") String username,@Param("password") String password);
<!--User checkLoginByParam(@Param("username") String username,@Param("password") String password);-->
<select id="checkLoginByParam" resultType="User">
select * from t_user where username=#{username} and password=#{password}
</select>
总结
所有获取传传递值的情况可以分为两种
a>实体类型类型参数
b>使用@Param标识参数
六.MyBatis的各种查询功能
1. 查询一个实体类对象
1.若查询出的数据只有一条
- a>可以通过实体类对象收
- b>可以通过list集合接收
- c>可以通过Map集合来接收
/**
* 根据id查询用户信息
*/
User getUserId(@Param("Uid") Integer id);
<!--User getUserId(@Param("Uid") Integer id);-->
<select id="getUserId" resultType="User">
select * from t_user where id=#{Uid}
</select>
2.查询一个list集合
可以通过设置返回值为List
/**
* 查询所有的用户信息
*/
List<User> getAllUser();
<!--List<User> getAllUser();-->
<select id="getAllUser" resultType="User">
select * from t_user
</select>
3、查询单个数据
/** MyBatis中设置了默认的类型别名
* Java.lang.Integer-->int,integer
* int-->_int,_integer
* Map-->map
* String-->string
*/
/**
* 查询用户信息总记录数
*/
Integer getCount();
<!--Integer getCount();-->
<!--resultType 也可以写Integer integer int Int 类型别名不区分大小写-->
<select id="getCount" resultType="java.lang.Integer">
select count(*) from t_user
</select>
4、查询一条数据为map集合
/**
* 根据id查询用户信息为一个map集合
*/
Map<String,Object>getUserByIdToMap(@Param("id") Integer id);
<!--Map<String,Object>getUserByIdToMap(@Param("id") Integer id);-->
<select id="getUserByIdToMap" resultType="map">
select * from t_user where id=#{id}
</select>
结果:{password=123456, sex=男, id=1, age=23, email=123.@qq.com, username=zkkk}
5、查询多条数据为map集合
方法一 用list集合包含map集合
List<Map<String,Object>>getAllUserByListMap();
<!--List<Map<String,Object>>getAllUserByListMap();-->
<select id="getAllUserByListMap" resultType="map">
select * from t_user
</select>
重点
注意此时的resultType必须为map对象,因为查询的所有user对象被一一存入map中然后将每个map在存放在list集合中如果返回值是user的话,那么你会发现他其实list存放的不是多个包含User的map集合,而仅仅是多个User对象存储在list中,并未存放在map中
public void getAllUserByListMap(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
List<Map<String, Object>> allUserByListMap = mapper.getAllUserByListMap();
System.out.println(allUserByListMap);
System.out.println(allUserByListMap);
//System.out.println(allUserByListMap.get(0));
for (Map<String,Object> map: allUserByListMap){
System.out.println(map);
System.out.println(map.get("id"));
}
}
输出结果
[{password=123456, sex=男, id=1, age=23, email=123.@qq.com, username=zkkk}, {password=123456, sex=男, id=4, age=23, email=1281628436@qq.com, username=admin}, {password=123456, sex=男, id=7, age=23, email=123.@qq.com, username=admin}, {password=123456, sex=男, id=8, age=23, email=123.@qq.com, username=admin}, ]
{password=123456, sex=男, id=1, age=23, email=123.@qq.com, username=zkkk}
1
{password=123456, sex=男, id=4, age=23, email=1281628436@qq.com, username=admin}
4
{password=123456, sex=男, id=7, age=23, email=123.@qq.com, username=admin}
7
{password=123456, sex=男, id=8, age=23, email=123.@qq.com, username=admin}
8
如果是resultType返回值是User的话,输出内容,我们通过获得list集合中每一个元素map的key判断list集合中的元素为map集合
<!--List<Map<String,Object>>getAllUserByListMap();-->
<select id="getAllUserByListMap" resultType="user">
select * from t_user
</select>
他输出了所有的内容但是会报一个没有key的错误,同时从输出上也能看出来这是一个list集合中包含着多个User对象
@Test
public void getAllUserByListMap(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
List<Map<String, Object>> allUserByListMap = mapper.getAllUserByListMap();
//System.out.println(allUserByListMap);
System.out.println(allUserByListMap);
System.out.println(allUserByListMap.get(0).get("id"));
//for (Map<String,Object> map: allUserByListMap){
// System.out.println(map);
// System.out.println(map.get("id"));
//
//}
}
结果
[User{id=1, username='zkkk', password='123456', age=23, sex='男', email='123.@qq.com'}, User{id=4, username='admin', password='123456', age=23, sex='男', email='1281628436@qq.com'}, User{id=7, username='admin', password='123456', age=23, sex='男', email='123.@qq.com'}, User{id=8, username='admin', password='123456', age=23, sex='男', email='123.@qq.com'}, User{id=9, username='admin', password='123456', age=23, sex='男', email='123.@qq.com'}, User{id=10, username='admin', password='123456', age=23, sex='男', email='123.@qq.com'}, User{id=11, username='Lisi', password='123456', age=12, sex='男', email='123456'}, User{id=12, username='Lisi', password='123456', age=12, sex='男', email='123456'}, User{id=13, username='Lisi', password='123456', age=12, sex='男', email='123456'}, User{id=14, username='Lisi', password='123456', age=12, sex='男', email='123456'}, User{id=15, username='Lisi', password='123456', age=12, sex='男', email='123456'}, User{id=16, username='Lisi', password='123456', age=12, sex='男', email='123456'}, User{id=17, username='Lisi', password='123456', age=12, sex='男', email='123456'}, User{id=18, username='Lisi', password='123456', age=12, sex='男', email='123456'}, User{id=19, username='Lisi', password='123456', age=12, sex='男', email='123456'}, User{id=20, username='Lisi', password='123456', age=12, sex='男', email='123456'}]
java.lang.ClassCastException: com.cn.cslg.mybatis.pojo.User cannot be cast to java.util.Map
方法二通过注释@mapkey来直接返回多个不同的map
可以在mapper接口的方法上添加@MapKey注解,此时就可以将每条数据转换的map集合作为值,以某个字段的值作为键,比如id,放在同一个map集合里面
/**
* 查询所有用户信息为map集合
*/
@MapKey("id")
Map<String,Object> getAllUserToMap();
<select id="getAllUserToMap" resultType="map">
select * from t_user
</select>
@Test
public void getUserByIdMap(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
Map<String, Object> userByIdToMap = mapper.getUserByIdToMap(1);
//System.out.println(userByIdToMap.get("username"));
System.out.println(mapper.getUserByIdToMap(1));
System.out.println(mapper.getAllUserToMap());
}
输出结果:
{1={password=123456, sex=男, id=1, age=23, email=123.@qq.com, username=zkkk}, 4={password=123456, sex=男, id=4, age=23, email=1281628436@qq.com, username=admin}, 7={password=123456, sex=男, id=7, age=23, email=123.@qq.com, username=admin}, 8={password=123456, sex=男, id=8, age=23, email=123.@qq.com, username=admin}, }