前言
在学习Mybatis的使用时,我遇到了各种各样的坑下面就是我在Mybatis的学习中遇到的问题和自己总结的解决方法,希望能够帮助到你们。
# mybatis介绍 mybatis介绍 MyBatis 是一款优秀的持久层框架 特征: 1、支持自定义 SQL(非自定义SQL:hebineate)、存储过程以及高级映射。 2、MyBatis解决JDBC 代码以及设置参数和获取结果集的工作。 3、MyBatis通过XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
mybatis原理
在学习mybatis原理时我不太明白,但通过自己对mybatis使用几次以后就有了自己的一些理解。如果各位也和我一样的话建议先自己动手完成以下增删改查的应用以后在来学习原理:
mybatis流程图
MyBatis原理
MyBatis应用程序根据XML配置文件创建SqlSessionFactory,SqlSessionFactory在根据配置,配置来源于两个地方,一处是配置文件,一处是Java代码的注解,获取一个SqlSession。SqlSession包含了执行sql所需要的所有方法,可以通过SqlSession实例直接运行映射的sql语句,完成对数据的增删改查和事务提交等,用完之后关闭SqlSession。
mybatis使用流程
1. 引出依赖
分别引入mybatis和mysql的依赖
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
导入依赖成功的话会生成mysql和mybatis依赖文件
这两个依赖是我们使用mybatis的基础
2.配置全局配置文件(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">
<!--根标签-->
<configuration>
<!--配置数据源-->
<environments default="development">
<!--id:环境的唯一标识-->
<environment id="development">
<!--事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源类型-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/exercise"/>
<property name="username" value="root"/>
<property name="password" value="******"/>
</dataSource>
</environment>
</environments>
</configuration>
需要关注的数据:
username: 账户名
password :账户密码
url :使用的数据库 jdbc:mysql://localhost:3306/库名/
关于全局配置更详细的使用:
参考文档:https://mybatis.org/mybatis-3/zh/configuration.html#
3.与数据库表对应pojo类(Class.java)
pojo类生成的方式:
方式一:手写:
对应关系:
类名--表名
属性名--列表名
属性类型--列表类型
还需要 set,get方法
方式二:通过连接数据库自动生成
需要填写账户名,密码和需要操作的库名
右键需要导入的表
找到需要导入的位置 ,点击ok就会给我们自动生成对应数据库表的类,属性和get、set方法
修改package为我们文件当前所在路径
生成的Class类如下所示:
public class Class {
private long c_id;
private String c_name;
public Class() {
}
public Class(long c_Id, String c_Name) {
this.c_id = c_Id;
this.c_name = c_Name;
}
public long getC_Id() {
return c_id;
}
public void setCId(long c_Id) {
this.c_id = c_Id;
}
public String getC_Name() {
return c_name;
}
public void setCName(String c_Name) {
this.c_name = c_Name;
}
}
与之对应的class表
4.Mapper接口文件(ClassMapper.java)
public interface ClassMapper {
//增
public void insertClass(Class c);
//删
public void deleteClass(long id);
//改
public void updateClass(@Param("c_id") long c_id,@Param("c_name") String c_name);
}
5.配置与接口文件对应的mapper.xml文件(ClassMapper.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,命令空间:保证命名空间唯一,一般是对应的mapper.java的包全路径-->
<mapper namespace="org.example.mapper.ClassMapper">
<!--
selectStudentById
select * from Student where SID = XXX
-->
<!--
select标签:查询操作
id属性:statement的id,用于表示定义的SQL,在同一个命名空间中id是不允许重复的
#{XXX}:输入参数的占位符,避免SQL注入
parameterType:输入参数类型
resultType:指定结果集类型
-->
<insert id="insertClass" parameterType="org.example.pojo.Class">
insert into class(c_id,c_name) values (#{c_id},#{c_name})
</insert>
<delete id="deleteClass" parameterType="long">
delete from Class where c_id = #{id};
</delete>
<update id="updateClass" >
update Class set c_name =#{c_name} where c_id = #{c_id}
</update>
</mapper>
6.在全局配置文件中引入mapper配置文件
<!--引入mapper配置文件-->
<mappers>
<mapper resource="mapper/StudentMapper.xml"/>
<mapper resource="mapper/ClassMapper.xml"/>
</mappers>
7.测试方法的实现
public static void insert() throws IOException {
//拿到全局配置文件
String resource = "mybatis-config.xml";
//mybbatis提供了Resources类获取配置文件流
try {
InputStream resourceAsdept = Resources.getResourceAsStream(resource);
//创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsdept);
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过反射机制来获取到mapper实例
ClassMapper mapper = sqlSession.getMapper(ClassMapper.class);
Class c = new Class(4, "暗影岛");
mapper.insertClass(c);
sqlSession.commit();
System.out.println("添加成功");
} catch (IOException e) {
e.printStackTrace();
}
}
测试方法的操作流程
1.通过mapper提供的Resources获取配置文件流
2.创建会话工厂
3.通过反射方法获取mapper实例
4.实现数据库操作
5.提交事务
查看mysql是否添加成功
以上全部内容就是一个完整的mybatis的使用过程
mybatis中遇到的问题及解决方法
1.没有引入mysql依赖
Error querying database. Cause: java.sql.SQLException: Error setting driver on UnpooledDataSource. Cause: java.lang.ClassNotFoundException: Cannot find class: com.mysql.cj.jdbc.Driver
解决方法在pom.xml中引入mysql依赖
2.配置文件中数据库操作语言与pojo类中的属性名大小写不一致
如下我们输入的参数类型为pojo.Class类型那么我们就需要保证
#{}中内如与我们Class类中属性名完全一致,大小写也需要一致
<insert id="insertClass" parameterType="org.example.pojo.Class">
insert into class(c_id,c_name) values (#{c_id},#{c_name})
</insert>
如果不一致会导致如下异常
3.没有提交事务
如果我们不在增删改操作后不进行事务提交的话,那么我们在数据库中查询时候没有我们的操作信息,所以需要我们手动提交事务
4.多组数据传入无法识别
当我们需要多组数据传入xml配置文件时,xml无法识别传入数据类型
public void updateClass(@Param("c_id") long c_id,@Param("c_name") String c_name);
解决方法:
1.添加@Param注解
2.pojo中写一个传入多组数据的类
3.两组数据时,可以采用map的形式传入
推荐使用第一种
XML形式使用Mybatis需要注意点:
基于xml形式需要遵循一定的规则:
1、xml配置文件中的命名空间和指向接口文件的地址(全路径)
2、mapper.java接口文件中的方法名和mapper.xml中Statement的id保持一致
3、mapper.java接口中方法参数和mapper.xml中Statement的parameterType或parameterMap的类型一致
4、mapper.java接口中方法返回值类型和mapper.xml中mapper.xml文件中Statement的resultType或resultMap类型一致
通过注解的方法使用mybatis
创建表对应的pojo类型
package org.example.pojo;;
import java.util.Date;
public class Student {
private int s_Id;
private String s_Name;
private String sex;
private Date birthday;
private String qq;
private long c_Id;
public Student(){
}
public Student(int s_Id, String s_Name, String sex, Date birthday, String qq, long c_Id) {
this.s_Id = s_Id;
this.s_Name = s_Name;
this.sex = sex;
this.birthday = birthday;
this.qq = qq;
this.c_Id = c_Id;
}
public int getSId() {
return s_Id;
}
public void setSId(int s_Id) {
this.s_Id = s_Id;
}
public String getSName() {
return s_Name;
}
public void setSName(String s_Name) {
this.s_Name = s_Name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(java.sql.Date birthday) {
this.birthday = birthday;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
public long getCId() {
return c_Id;
}
public void setCId(long c_Id) {
this.c_Id = c_Id;
}
@Override
public String toString() {
return "Student{" +
"sId=" + s_Id +
", sName='" + s_Name + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
", qq='" + qq + '\'' +
", cId=" + c_Id +
'}';
}
}
给定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,命令空间:保证命名空间唯一,一般是对应的mapper.java的包全路径-->
<mapper namespace="org.example.mapper.StudentMapper">
</mapper>
全局配置文件中引入mapper.xml
<mappers>
<mapper resource="mapper/StudentMapper.xml"/>
<mapper resource="mapper/ClassMapper.xml"/>
</mappers>
在接口文件中通过注解完成CRUD操作
/**
* @Select 注解即xml配置文件中select标签
*
* @Results注解和xml 配置文件中ResultMap标签使用类似
*/
@Results(id = "studentResult",
value = {
//column 为数据库中列明 可以不区分大小写
//property 为pojo中类的属性 ,需要区分大小写
@Result(column = "s_id" ,property = "s_id"),
@Result(column = "s_name",property = "s_name"),
@Result(column = "sex", property = "sex"),
@Result(column = "birthday", property = "birthday"),
@Result(column = "qq",property = "qq"),
@Result(column = "c_id",property = "c_id")
})
//方法上面添加注解注解内容为mysql语句
@Select("select * from student where s_id = #{id}")
public Student selectUserById(int id);
测试方法和xml形式相同
显示执行细节日志
log4j日志
在资源路径下创建log4j.properties
## debug 级别
log4j.rootLogger=DEBUG,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout = org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd-HH\:mm\:ss,SSS} [%t] [%c] [%p] - %m%n
log4j.logger.com.tulun=DEBUG /
##输出sql 语句
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG</strong>
pom.xml中引入log4j依赖
<!--日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
</dependency>