认识mybatis
mybatis和JDBC的作用一致,是用来对数据库执行操作的,但是优越在:
支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
要在项目中使用mybatis,需要mybatis和mysql-connector-java(相应数据库即可)两个jar包。
在配置上,需要给每张表一个映射文件mapper.xml,以及全局的mybatis-config.xml。
来看看如何使用mybatis。
一、利用maven或者手动导入jar包。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
二、利用Mysql建库建表(或者其他数据库)。步骤如下(或者用可视化工具更快):
1、mysql -u root -p 然后输入密码登陆
2、create database testbase 或者 use testbase 选择一个数据库
3、任意建两张表,再插入部分数据:
三、建立如下结构:
其中,entity中的类可以理解是表中的记录项,mappers中的则用来提供增删查改接口,mapper配置文件和mybatis全局配置文件放在resources下。
具体来说,entity中的实体类的属性是和表的列相对应的,由mapper.xml完成二者之间的映射关系。而mapper文件夹下的mapper.java则是提供了操作数据库的接口,实际上它并不需要实现类(这里的impl文件下的实现类是用来方便使用而封装的)。
四、具体介绍
1、entity(以下均以Dragon为例,Warrior只需要改个名就行了)
//Dragon.java
package cn.ldy.entity;
public class Dragon {
private int id;
private String field;
private String name;
private int level;
private String attribute;
@Override
public String toString() {
return "Dragon{" +
"id=" + id +
", field='" + field + '\'' +
", name='" + name + '\'' +
", level=" + level +
", attribute='" + attribute + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
}
2、mappers
//DragonMapper.java
package cn.ldy.mappers;
import cn.ldy.entity.Dragon;
import java.io.IOException;
import java.util.List;
public interface DragonMapper {
public void insertDragon(Dragon Dragon) throws IOException;
public void deleteDragonById(int id) throws IOException;
public void deleteAll() throws IOException;
public void updateDragon(Dragon Dragon);
public List<Dragon> queryAll();
public Dragon queryDragonById(int id);
}
3、mappers.impl
//DragonMapperImpl.java
package cn.ldy.mappers.impl;
import cn.ldy.entity.Dragon;
import cn.ldy.mappers.DragonMapper;
import cn.ldy.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
import java.util.List;
public class DragonMapperImpl {
private static SqlSession sqlSession;
public static void insertDragon(Dragon dragon) {
/*
一种方式
sqlSession = MybatisUtil.getSession();
sqlSession.insert("insertDragon", dragon);
sqlSession.commit();
sqlSession.close();
*/
//另一种方式
sqlSession = MybatisUtil.getSession();
DragonMapper dragonMapper = sqlSession.getMapper(DragonMapper.class);
try{
dragonMapper.insertDragon(dragon);
System.out.println(dragon.toString() + "inserted!");
sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void deleteDragonById(int id) {
sqlSession = MybatisUtil.getSession();
DragonMapper dragonMapper = sqlSession.getMapper(DragonMapper.class);
try{
dragonMapper.deleteDragonById(id);
sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void deleteAll() {
sqlSession = MybatisUtil.getSession();
DragonMapper dragonMapper = sqlSession.getMapper(DragonMapper.class);
try{
dragonMapper.deleteAll();
sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void updateDragon(Dragon dragon) {
sqlSession = MybatisUtil.getSession();
DragonMapper dragonMapper = sqlSession.getMapper(DragonMapper.class);
dragonMapper.updateDragon(dragon);
sqlSession.commit();
}
public static List<Dragon> queryAll() {
sqlSession = MybatisUtil.getSession();
DragonMapper dragonMapper = sqlSession.getMapper(DragonMapper.class);
List<Dragon> list = dragonMapper.queryAll();
sqlSession.commit();
return list;
}
public static Dragon queryDragonById(int id) {
sqlSession = MybatisUtil.getSession();
DragonMapper dragonMapper = sqlSession.getMapper(DragonMapper.class);
Dragon dragon = dragonMapper.queryDragonById(id);
sqlSession.commit();
return dragon;
}
}
调用这些方法有两种方式,这里首先利用util工具类产生一个SqlSession对象。在工具类中,读取了相应的xml配置文件,利用会话getMapper方法就可以直接调用在xml文件中实现了的接口方法了。
4、util
//MybatisUtil.java
package cn.ldy.util;
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.Reader;
public class MybatisUtil {
private static String resource="mybatis-config.xml";
static Reader reader;
static{
try {
reader= Resources.getResourceAsReader(resource);
} catch (IOException e) {
e.printStackTrace();
}
}
private static SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}
该工具类用来产生一个SqlSession对象。
5、resources
//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>
<settings>
<setting name="lazyLoadingEnabled" value="false" />
</settings>
<typeAliases>
<!--给实体类取别名,方便在mapper配置文件中使用 -->
<typeAlias alias="Dragon" type="cn.ldy.entity.Dragon" />
<typeAlias alias="Warrior" type="cn.ldy.entity.Warrior" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!--连接数据库的属性,同JDBC -->
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<!-- ?serverTimezone=GMT%2B8 这部分可以不加,这是由于我这里Mysql报了时区错误-->
<property name="url" value="jdbc:mysql://localhost:3306/testbase?serverTimezone=GMT%2B8" />
<property name="username" value="root" />
<property name="password" value="" />
</dataSource>
</environment>
</environments>
<!--这里要填入具体的配置文件的地址 -->
<mappers>
<mapper resource="mappers/DragonMapper.xml" />
<mapper resource="mappers/WarriorMapper.xml" />
</mappers>
</configuration>
在typeAliases中填写的别名,是为了在具体的xml配置文件中方便表示。
如果不设置,后面的parameterType等都要写全。
6、resources.mappers
//DragonMapper.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="cn.ldy.mappers.DragonMapper">
<!--由于在mybatis-config.xml里配置了别名,所以不必写出完整的cn.ldy.entity.Dragon -->
<insert id="insertDragon" parameterType="Dragon">
insert into dragon(field,name,level,attribute)
values(#{field}#,#{name},#{level},#{attribute})
</insert>
<!--虽然返回的是列表,但是resultType填写的应该是容器中的类型 -->
<select id="queryAll" resultType="Dragon">
select * from dragon
</select>
<select id="queryDragonById" parameterType="int" resultType="Dragon">
select * from dragon
where id = #{id}
<select>
<delete id="deleteAll">
delete from dragon
</delete>
<delete id="deleteDragonById" parameterType="int">
delete from dragon
where id = #{id}
</delete>
<update id="updateDragon" parameterType="Dragon">
update dragon
<set>
field = #{field},
name = #{name},
level = #{level},
attribute = #{attribute}
</set>
where id = #{id}
</update>
</mapper>
namespace中是个例外,即使设置了别名也要写全路径。
后面的四种类标签则对应增删查改四种方法,其中id名和接口中的方法名保持一致,参数类型parameterType和返回类型resultType也是。注意的是,如果类型是List这样的容器,填的仍然是容器中的类型。具体的实现中,用 #{}的格式作占位符,内部名字没有要求,但是最好和对应属性名一致。
五、测试
package cn.ldy.test;
import cn.ldy.entity.Dragon;
import cn.ldy.entity.Warrior;
import cn.ldy.mappers.impl.DragonMapperImpl;
import cn.ldy.mappers.impl.WarriorMapperImpl;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Dragon> dragonList= DragonMapperImpl.queryAll();
System.out.println(dragonList.toString());
List<Warrior> warriorList = WarriorMapperImpl.queryAll();
System.out.println(warriorList.toString());
}
}
输出结果:
7、流程
回顾一下,发现流程是这样的,工具类解析mybatis-config.xml,返回一个会话,返回一个代理类(貌似是)使接口可以“执行”对应xml里的语句实现,提交会话,执行操作。
可以发现,将接口和实现对应起来的,是id这个属性,如果selectDragonById和selectDragonByname两个接口以及对应的xml中的实现,那么我们在执行getMapper返回的那个代理类的selectDragonById的时候,由于它与xml文件里的id=“selectDragonById”一致,所以执行的就是它的实现。
那么在这个例子中,有DragonMapper.xml和WarriorMapper.xml两个配置文件,里面都有id = "queryAll",当我使用DragonMapperImpl.queryAll()的时候,怎么知道对应的是哪个配置文件里的queryAll呢? 答案就是命名空间namespace√。