操作的最开始要再pom文件中导入mybatis的坐标
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<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>
</dependency>
目录:
一、mybatis的第一个demo
二、mybatis构建dao层以及动态sql
三、mybatis中对于java类型和数据库数据类型的转换,插件使用
四、mybatis的多表操作基于xml
=======================================
一、demo操作步骤:
【一开始就跟着做就行,写完运行出来后再看注释】
1.配置sqlmapconfig.xml——数据库链接与映射文件配置
2.创建数据对象与测试代码
3.配置映射文件
1.sqlmapconfig.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>
<!-- 导入properties文件-->
<properties resource="com/wzy/mapper/jdbc.properties"></properties>
<!-- 配置数据源环境,可包括多个环境,可设置默认值-->
<environments default="development">
<environment id="development">
<!-- 事务管理,设置事务管理类型是JDBC-->
<!-- JDBC依赖于从数据源得到的连接来管理事务作用域-->
<!-- MANAGED让容器管理事务的整个声明周期,默认是关闭连接-->
<transactionManager type="JDBC"></transactionManager>
<!-- 设置数据源类型-->
<!-- UNPOOLED:每次请求时打开和关闭连接-->
<!-- POOLED:一次连接,之后每次请求时从数据池中拿-->
<!-- JNDI:-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
</configuration>
jdbc.properties文件,老朋友了,不介绍
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
user=root
password=123456
2.demo用的数据库表只有简单的三个字段
下面是user实体类
package com.wzy.domain;
/**
* @author:wzy
* @date:2021/1/29-01-29-10:12
*/
public class user {
private int id;
private String name;
private String password;
public int getId() {
return id;
}
@Override
public String toString() {
return "user{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
实体类定义完了后进行测试操作,测试操作要有增删改查四种
随便搞一个类,由于只是简单测试与数据库交互,这里不编写前端,就在内部自创实体对象进行操作
测试添加功能
@Test
public void test2() throws IOException {
user user = new user();
user.setName("wzywzywzyaljx");
user.setPassword("323232");
// 获得sqlmapconfig文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 获得session工厂对象
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 获得session会话对象,若为true则不用手动提交事务,若为空或者为false则需要手动提交
SqlSession sqlSession = build.openSession(true);
// 执行操作,输入参数namespace+id,即usermapper文件中的namespace和id
int insert = sqlSession.insert("usermapper.insert", user);
// 需要手动提交事务
// sqlSession.commit();
// 释放session会话资源
sqlSession.close();
测试查找功能
@Test
public void test1() throws IOException {
// 获得sqlmapconfig文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 获得session工厂对象
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 获得session会话对象
SqlSession sqlSession = build.openSession();
// 执行操作,输入参数namespace+id,即usermapper文件中的namespace和id
List<user> userList = sqlSession.selectList("usermapper.findAll");
System.out.println(userList);
// 释放session会话资源
sqlSession.close();
}
测试修改功能
@Test
public void test3() throws IOException {
user user = new user();
user.setId(3);
user.setName("wzywzywzyaljx");
user.setPassword("323232");
// 获得sqlmapconfig文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 获得session工厂对象
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 获得session会话对象
SqlSession sqlSession = build.openSession();
// 执行操作,输入参数namespace+id,即usermapper文件中的namespace和id
sqlSession.update("usermapper.update",user);
// 需要手动提交事务
sqlSession.commit();
// 释放session会话资源
sqlSession.close();
}
测试删除功能
@Test
public void test4() throws IOException {
// 获得sqlmapconfig文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 获得session工厂对象
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 获得session会话对象
SqlSession sqlSession = build.openSession();
// 执行操作,输入参数namespace+id,即usermapper文件中的namespace和id
sqlSession.delete("usermapper.delete",4);
// 需要手动提交事务
sqlSession.commit();
// 释放session会话资源
sqlSession.close();
}
测试条件查找功能
@Test
public void test5() throws IOException {
// 获得sqlmapconfig文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 获得session工厂对象
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 获得session会话对象
SqlSession sqlSession = build.openSession();
// 执行操作,输入参数namespace+id,即usermapper文件中的namespace和id
user o = sqlSession.selectOne("usermapper.findbyid", 5);
System.out.println(o);
// 释放session会话资源
sqlSession.close();
}
⭐⭐注意:sqlsession工厂创造出的对象的opensession方法有一个布尔类型的参数,默认不填写为false,即事务不自动提交,需要手动调用commit方法提交事务;填写为true则为自动提交
3.配置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="usermapper">
<!-- #{}内不能为空,一个为空则这个xml文件就毁了!!!-->
<select id="findAll" resultType="user">
select * from user
</select>
<insert id="insert" parameterType="com.wzy.domain.user">
insert into user values(#{id},#{name},#{password})
</insert>
<update id="update" parameterType="com.wzy.domain.user">
update user set name=#{name},password=#{password} where id=#{id}
</update>
<delete id="delete" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
<select id="findbyid" resultType="user">
select * from user where id=#{id}
</select>
</mapper>
测试方法中的sqlsession对象中有许多方法配合数据库操作调用
查询所有信息有selectlist,查询单个实体有selectone,删除delete,插入insert,修改update
这些方法中第一个形参为映射名——即mapper文件中mapper标签的namespace属性值+其中增删改查属性标签中的id属性值;第二个参数则是数据库交互所需的数据
⭐mapper文件中语句标签的传入数据类型写入parametertype属性中,返回数据类型写入resulttype类型中,这里的类型可以依靠配置sqlmapconfig.xml文件中的typealiases标签来简化
<typeAliases>
<typeAlias type="com.wzy.domain.user" alias="user"/>
</typeAliases>
如上配置后parametertype与resulttype两个属性值中填写user就相当于填写com.wzy.domain.user
⭐传入参数在语句中不再使用?做占位符,改为使用#{ },其中必须要写东西【不然会使整个xml文件报错】,值需要与实体类中的属性名相同
写好mapper文件后需要告知mybatis,因此需要在sqlmapconfig.xml中配置文件位置
<!-- 加载映射文件-->
<mappers>
<!-- <package name=""/>包下面的类实现-->
<!-- class是用注解-->
<mapper resource="com/wzy/mapper/UserMapper.xml"/>
</mappers>
完成后即可测试上面写的增删改查方法
============================================
二、
mybatis如何应用到dao层中?代理方式
只需要编写接口方法和对应的映射配置以及sql语句,使用时读取接口文件即可
操作步骤:
1.编写sqlmapconfig.xml,配置数据源
2.编写实体类、接口方法与映射文件mapper.xml
3.编写测试方法
1.同上面demo的数据源配置相同,简写配置也相同
2.这里编写简单的两个查询方法,注意这里是接口方法,实体类与上面demo相同
public interface UserMapper {
public List<user> findAll() throws IOException;
public user findById(int id);
}
再配置映射文件
<?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="wzy.Dao.UserMapper">
<!-- #{}内不能为空,一个为空则这个xml文件就毁了!!!-->
<select id="findAll" resultType="user">
select * from user
</select>
<select id="findById" parameterType="int" resultType="user">
select * from user where id=#{id}
</select>
</mapper>
⭐⭐注意:这里映射中的id属性值必须与接口方法名相同
3.测试类中的方法
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 只需要接口与配置mapper文件,即代理方式,只需要注意方法名、形参与返回值是否一致
List<user> all = mapper.findAll();
user byId = mapper.findById(5);
System.out.println(all);
System.out.println(byId);
}
⭐动态sql——在mapper文件中实现
配置文件的标签内部有where标签与if标签,可根据传入参数的情况来动态改变sql语句
条件查询语句——无实体传入则selectall,有实体传入则看实体内部数据的情况来变化SQL语句,配置如下
其中name用的是模糊查询的格式,%代表任意长度的字符,_代表任意一个字符,like的模糊查询可以灵活运用这两个通配符
<select id="findByCondition" parameterType="user" resultType="user">
select * from user
<where>
<if test="id!=0">and id=#{id}</if>
<if test="name!=null">and name like concat("%",#{name},"%")</if>
<if test="password!=null">and password =#{password}</if>
</where>
</select>
可根据if中test的条件是否满足来决定是否添加标签中的元素,从而做到sql语句的动态变化
另外一种查询是同一属性的多个值
select * from user where id in(?,?,?)
括号内有多少个值不定,这就需要动态sql的foreach标签
如下
<select id="findByIDs" parameterType="list" resultType="user">
select * from user
<where>
<foreach collection="list" open="id in(" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
其中参数传入list,where标签后以“id in(”开头,以“)”结尾,中间每一项都为id,用“,”分隔开
测试
@Test
public void test2() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 只需要接口与配置mapper文件,即代理方式,只需要注意方法名、形参与返回值是否一致
ArrayList<Integer> integers = new ArrayList<Integer>();
integers.add(1);
integers.add(5);
List<user> byCondition = mapper.findByIDs(integers);
System.out.println(byCondition);
sqlSession.close();
}
================================================
三、有时候java中实体类的数据类型和数据库存储的数据类型不相同
如Java类型为date而存入数据库的类型为long,即date以时间戳形式存入数据库
这种情况就需要自定义类型转换
步骤:
1.准备好数据库字段long类型,java实体类添加date属性
2.编写自定义的类型转换类
3.配置自定义的类到sqlmapconfig.xml中
=
1.自行改
2.继承BaseTypeHandler<>类,泛型中写date类型,重写父类的四个方法,方法的作用看注释
package wzy.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
/**
* @author:wzy
* @date:2021/1/30-01-30-17:59
*/
public class DateTypeHandler extends BaseTypeHandler<Date> {
// 将java类型转换为数据库需要的类型
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
long time = date.getTime();
preparedStatement.setLong(i,time);
}
// 将数据库中的类型转换成java类型
// String参数是要转换的字段名称
// ResultSet是查询出的结果集
public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
// 获得结果集中需要的数据(即long型)转为java的date类型
long aLong = resultSet.getLong(s);
Date date = new Date(aLong);
return date;
}
// 将数据库中类型转换成Java类型
public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
long aLong = resultSet.getLong(i);
Date date = new Date(aLong);
return date;
}
// 将数据库中类型转换成Java类型
public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
long aLong = callableStatement.getLong(i);
Date date = new Date(aLong);
return date;
}
}
3.配置
即把类的位置放入handler属性值中即可
<typeHandlers>
<typeHandler handler="wzy.handler.DateTypeHandler"/>
</typeHandlers>
此后date类型的数据存入数据库都会经过这个类型处理器转换为long类型时间戳形式存入数据库
================================================
分页助手插件的使用
步骤:
1.导入pom坐标
2.配置到sqlmapconfig.xml中
3.测试使用
=
1.
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.1</version>
</dependency>
配置进去,这里使用的数据库为mysql,照写就行
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
</plugin>
</plugins>
也可以当作前面动态sql条件查询的测试
下面是分页工具可以给到的功能,如返回当前页等
@Test
public void test1() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 只需要接口与配置mapper文件,即代理方式,只需要注意方法名、形参与返回值是否一致
user user = new user();
// user.setId(6);
// user.setName("");
// user.setPassword("123");
// 设置分页相关参数 当前页+每页显示条数
PageHelper.startPage(2,2);
List<user> byCondition = mapper.findByCondition(user);
// System.out.println(byCondition);
for (user user1:byCondition
) {
System.out.println(user1);
}
// 获得与分页相关的参数
PageInfo<wzy.domain.user> userPageInfo = new PageInfo<user>(byCondition);
System.out.println("当前页"+userPageInfo.getFirstPage());
System.out.println("每页显示条数"+userPageInfo.getPageSize());
System.out.println("总条数"+userPageInfo.getTotal());
System.out.println("上一页"+userPageInfo.getPrePage());
System.out.println("下一页"+userPageInfo.getNextPage());
System.out.println("是否第一个"+userPageInfo.isIsFirstPage());
System.out.println("是否最后一个"+userPageInfo.isIsLastPage());
System.out.println("总页数"+userPageInfo.getPages());
sqlSession.close();
}
==================================================
四、多表操作
统一操作步骤都是——编写接口与mapper.xml文件,配置mapper.xml位置到sqlmapconfig.xml文件中,测试
表信息:https://pan.baidu.com/s/1padyOWYXl9BF75P99wHHIg
提取码:aljx
为了接收数据库查询返回的数据
实体类orders属性如下
private int id;
private Date ordertime;
private double total;
private user user;
实体类role属性如下
private int id;
private String roleName;
private String roleDesc;
实体类user属性如下
private int id;
private String username;
private String password;
private Date birthday;
// 描述当前用户有几个订单
private List<orders> ordersList;
// 描述当前用户具备什么角色
private List<role> roleList;
以上为基础生成gettersetter方法即可
有orders、sys_user、sys_role、sys_user_role四张表
1)一对一操作
每一个订单都有一个用户信息,需要显示订单的同时显示订单对应的用户信息
2)一对多操作
每个用户可能有多个订单,需要显示用户信息的同时显示用户的多个订单信息
3)多对多操作
每个用户有可能有多个角色信息,每个角色信息可能对应有多个用户,因此需要有个中间表来存其中的关系,查询用户时将用户对应的角色信息也显示出来
⭐⭐以上面的java实体进行查询时,若不进行额外的对应配置则会报错,因此下面的配置意义是手动将数据库的字段与Java实体属性相互对应起来
1)一对一
接口略,mapper.xml文件,注意接口方法名与id属性值要求相同
<?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="wzy.Mapper.OrderMapper">
<resultMap id="orderMap" type="wzy.domain.orders">
<!-- 手动指定字段与实体属性的映射关系-->
<!-- column——数据表的字段名称-->
<!-- property——java实体的属性名称-->
<id column="oid" property="id"/>
<!-- 数据库主键用id标签,其余用result标签-->
<result column="ordertime" property="ordertime"/>
<result column="total" property="total"/>
<!-- 第一种手动配置,让数据库表的一列与一个实体属性对应-->
<!--<result column="uid" property="user.id"/>
<result column="username" property="user.username"/>
<result column="password" property="user.password"/>
<result column="birthday" property="user.birthday"/>-->
<!-- 第二种手动配置,property为实体orders中属性名,javatype为orders中的属性类型-->
<association property="user" javaType="user">
<id column="uid" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
</association>
</resultMap>
<select id="findorder" resultMap="orderMap">
select *,o.id oid from orders o,user u where o.uid=u.id
</select>
</mapper>
2)一对多
mapper.xml配置
<resultMap id="usermap" type="wzy.domain.user">
<id column="uid" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<!-- 配置集合-->
<collection property="ordersList" ofType="wzy.domain.orders">
<id column="oid" property="id"/>
<result column="ordertime" property="ordertime"/>
<result column="total" property="total"/>
</collection>
</resultMap>
<select id="findall" resultMap="usermap">
SELECT *,o.id oid FROM USER u,orders o WHERE u.id=o.uid
</select>
3)多对多
<resultMap id="roleall" type="wzy.domain.user">
<id column="userId" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<!-- 配置集合-->
<collection property="ordersList" ofType="wzy.domain.role">
<id column="roleId" property="id"/>
<result column="roleName" property="roleName"/>
<result column="roleDesc" property="roleDesc"/>
</collection>
</resultMap>
<select id="findroleall" resultMap="roleall">
SELECT * FROM USER u,sys_user_role sur,sys_role sr WHERE u.id=sur.userId AND sur.roleId=sr.id
</select>
配置只需要在sqlmapconfig.xml中配置mappers标签,其中mapper标签的resource属性值填写mapper.xml路径即可
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/OrderMapper.xml"/>
</mappers>
→统一编写测试
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 wzy.Mapper.OrderMapper;
import wzy.Mapper.UserMapper;
import wzy.domain.orders;
import wzy.domain.user;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author:wzy
* @date:2021/2/1-02-01-12:29
*/
public class test {
// 一对一——查询订单,每个订单附带user信息
@Test
public void test1() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
List<orders> findorder = mapper.findorder();
System.out.println(findorder);
for (orders order:findorder) {
System.out.println(order);
}
sqlSession.close();
}
// 一对多——查询user信息,每条信息附带user的所有订单
@Test
public void test2() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<user> findall = mapper.findall();
for (user user:findall) {
System.out.println(user);
}
sqlSession.close();
}
// 多对多——查询user,每条信息附带user的所有身份信息
@Test
public void test3() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<user> findall = mapper.findroleall();
for (user user:findall) {
System.out.println(user);
}
sqlSession.close();
}
}
输出打印成功即可
================================================