1. 为什么要使用Mybatis? 之前使用的都是JDBC,需要自己写Connection,Statement,ResultSet,这些其实只是一些辅助类。另一方面,如果需要访问不同的表,需要写对应的DAO,其中包含很多重复的代码,十分繁琐和枯燥。
使用Mybatis之后,只需要自己提供SQL语句,其他工作如建立连接,创建Statement以及异常处理都交给Mybatis去做。我们只需要关注在增查改删的操作层面上即可,而把技术细节封装在看不见的地方。
简单来说,使用Mybatis可以更简单、高效地操作数据库👀。
2. Hello Mybatis 2.1 新建mybatis-config.xml 使用IDEA创建普通java项目(quickstart模板)。
项目结构如下:
- src
- main
- java
- test
这里的java是代码的根目录,将mybatis-config.xml新建在这里。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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 > <typeAliases > <package name ="com.ssl.bean" /> </typeAliases > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://127.0.0.1:3306/cart?characterEncoding=UTF-8& serverTimezone=GMT" /> <property name ="username" value ="root" /> <property name ="password" value ="admin" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="com/ssl/bean/Order.xml" /> </mappers > </configuration >
在配置文件中需要提供ip、端口号、所连接的数据库、用户名、密码,在property标签中设置好,MySQL驱动也通过配置文件设置好。
typeAliases标签中的是起的别名,方便一会儿设置实体类的xml不用写完整路径,自动扫描com.ssl.bean下的类型,使得在后续配置文件Order.xml中使用resultType的时候,可以直接使用Order,而不必写全com.ssl.bean.Order
这里数据库order_和对应的实体类都需要提前新建好哇✔,我就不赘述了。
2.2 创建Order.xml 我这里查询的表是order_,对应的实体类为Order,所以新建的配置文件也应是Order.xml,名字要相同😶。路径和实体类位置一样,即com/ssl/bean/Order.xml
1 2 3 4 5 6 7 8 9 10 <?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.ssl.bean" > <select id ="listOrder" resultType ="Order" > select * from order_ </select > </mapper >
这里resultType直接填Order就🆗。
id中的名字一会儿调用的时候会用到。
这个配置文件就相当于JDBC中的DAO,需要其它方法,如增改删,在mapper标签中添加对应的SQL语句即可。
2.3 创建启动类
加载配置文件
根据配置文件创建SqlSessionFactory
打开会话
使用会话执行查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class TestMybatis { public static void main (String[] args) throws IOException { String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); List<Order> orders = sqlSession.selectList("listOrder" ); for (Order o : orders) { System.out.println("id: " + o.getId() + " uid: " + o.getUid()); } } }
流程
应用程序找Mybatis要数据
Mybatis根据mybatis-config.xml找到数据库
通过Order.xml执行SQL语句
将Order封装在集合中
返回Order集合
2.4 几个小问题 2.4.1 maven依赖 MySQL依赖
1 2 3 4 5 <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.17</version > </dependency >
Mybatis依赖
1 2 3 4 5 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.4</version > </dependency >
2.4.2 xml中&符号的使用 在mybatis-config.xml文件中,如果连接数据库的url要提交多个参数需要用到&,而在xml文件中直接使用&是不允许的,需要转换成实体进行使用。
< < 小于号
> > 大于号
& & 和
' ' 单引号
" " 双引号
2.4.3 IDEA编译问题 起初使用IDEA将上面都配置完之后,发现程序跑不起来,报错是找不到mybatis-config.xml文件。打开target的文件夹,发现编译完成的文件中没有xml文件。
这是因为IDEA默认对xml文件不进行编译,所以需要在pom.xml文件中的build标签 添加下面代码
1 2 3 4 5 6 7 8 9 <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > </resources >
即可将java文件夹下面的所有xml文件编译到target文件夹中。
3. Mybatis CRUD 在Order.xml中添加CRUD的SQL语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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.ssl.bean" > <insert id ="addOrder" parameterType ="Order" > insert into order_ values (null, #{uid}) </insert > <select id ="listOrder" resultType ="Order" > select * from order_ </select > <select id ="getOrder" parameterType ="_int" resultType ="Order" > select * from order_ where id=#{id} </select > <update id ="updateOrder" parameterType ="Order" > update order_ set uid=#{uid} where id=#{id} </update > <delete id ="deleteOrder" parameterType ="Order" > delete from order_ where id=#{id} </delete > </mapper >
在TestMybatis类中实现CRUD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 package com.ssl;import com.ssl.bean.Order;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;import java.util.List;public class TestMybatis { public static void main (String[] args) throws IOException { String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); listAll(sqlSession); System.out.println("------------------------------" ); Order order = new Order(); order.setUid(10 ); sqlSession.insert("addOrder" , order); System.out.println("新增一条记录" ); listAll(sqlSession); System.out.println("-------------------------------" ); Order order1 = sqlSession.selectOne("getOrder" , 3 ); System.out.println("id: " + order1.getId() + " uid: " + order1.getUid()); System.out.println("-------------------------------" ); Order order2 = new Order(); order2.setId(2 ); order2.setUid(100 ); sqlSession.update("updateOrder" , order2); System.out.println("修改一条记录" ); listAll(sqlSession); System.out.println("-------------------------------" ); sqlSession.delete("deleteOrder" , order2); System.out.println("删除一条记录" ); listAll(sqlSession); sqlSession.commit(); sqlSession.close(); } public static void listAll (SqlSession sqlSession) { List<Order> orders = sqlSession.selectList("listOrder" ); for (Order o : orders) { System.out.println("id: " + o.getId() + " uid: " + o.getUid()); } } }
注意:
获取数据库中一条数据的方法是selectOne!返回的是一个Order对象。
最后一定要加commit方法,否则添加的数据不会在数据库当中显示(我也不知道为啥。。😂记得加~)Mybatis不会自动提交,查询可以不提交,只显示内容。
_int对应java中的基本类型int,int对应Integer类。
4. Mybatis 更多查询 4.1 模糊查询 在Order.xml中添加
1 2 3 <select id ="listOrderByUid" parameterType ="string" resultType ="Order" > select * from order_ where uid like concat('%', '#{name}', '%') </select >
concat是MySQL中的字符串拼接函数;%是通配符,适配任意字符。
TestMybatis中这样写
1 List<Order> orders = sqlSession.selectList("listOrderByUid" , "s" );
这里我的表可能查不出结果。。会用就可以啦。
关于占位符的问题
如果是bean类型,Mybatis会自动调用其getter获取值,替换到相应的位置;
如果是其它类型,如string,_int,则会顺序填入,无所谓#{}中的字段是什么。
4.2 多条件查询 SQL语句中使用逻辑关联词连接条件就可以啦😜
使用的时候参数需要装在Map中,把这个Map作为参数传递进去。
1 2 3 4 Map<String,Object> params = new HashMap<>(); params.put("id" , 3 ); params.put("uid" , "c" ); List<Category> cs = session.selectList("listCategoryByIdAndName" ,params);
5. Mybatis 表关系 5.1 一对多 例如分类和产品的关系,一个分类下对应多个产品,这就是一对多的关系。
新建category表和product 表
category_
product_
因为是展示分类与产品一对多的关系,新建Category.xml(实体类Category这里就不多说了[其中有一个属性为List<Product> products]
,同样地,Product实体类也需要新建好),利用连接查询两表数据并返回List(使用collection标签把对应列的数据放在product对应的属性中 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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.ssl.bean" > <resultMap id ="categoryBean" type ="Category" > <id column ="cid" property ="id" /> <result column ="cname" property ="name" /> <collection property ="products" ofType ="Product" > <id column ="pid" property ="id" /> <result column ="pname" property ="name" /> <result column ="price" property ="price" /> </collection > </resultMap > <select id ="listCategory" resultMap ="categoryBean" > select c.id as cid, c.name as cname, p.id as pid, p.name as pname, p.price from category_ as c left join product_ as p on c.id=p.cid; </select > </mapper >
在mybatis-config.xml中添加映射
1 2 3 <mappers > <mapper resource ="com/ssl/bean/Category.xml" /> </mappers >
在启动类使用如下代码查询
1 2 3 4 5 6 7 List<Category> listCategory = sqlSession.selectList("listCategory" ); for (Category c : listCategory) { System.out.println(c); for (Product p : c.getProducts()) { System.out.println("\t" + p); } }
结果如图
5.2 多对一 对应的,产品与分类的关系则是多对一。
在Product实体类中添加Category category
属性,新建Product.xml(使用association标签将对应列的数据放在bean类当中 ),同样使用连接查询两表的数据(我喜欢把要查询的表作为左表( ̄▽ ̄)”好理解一些 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?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.ssl.bean" > <resultMap id ="productBean" type ="Product" > <id column ="pid" property ="id" /> <result column ="pname" property ="name" /> <result column ="price" property ="price" /> <association property ="category" javaType ="Category" > <id column ="cid" property ="id" /> <result column ="cname" property ="name" /> </association > </resultMap > <select id ="listProduct" resultMap ="productBean" > select p.id as pid, p.name as pname, p.price, c.id as cid, c.name as cname from product_ as p left join category_ as c on p.cid=c.id; </select > <select id ="getProduct" parameterType ="_int" resultMap ="productBean" > select p.id as pid, p.name as pname, p.price, c.id as cid, c.name as cname from product_ as p left join category_ as c on p.cid=c.id where p.id=#{id}; </select > </mapper >
添加映射,最后运行结果如下
5.3 多对多 如订单和产品的关系,一个订单可以包含多个产品,而一个产品也可以对应多个订单,它们两个是多对多的关系。
这里借助订单项这个表来建立它们之间的联系,每一条订单项对应一个订单中的一条数据。
order_
orderItem_(oid对应所属order的id,pid对应product的id)
新建Order.xml,连接三表进行查询(注意collection和association的嵌套 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?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.ssl.bean" > <resultMap id ="orderBean" type ="Order" > <id column ="id" property ="id" /> <result column ="code" property ="code" /> <collection property ="orderItems" ofType ="OrderItem" > <id column ="oiid" property ="id" /> <result column ="num" property ="num" /> <association property ="product" javaType ="Product" > <id column ="pid" property ="id" /> <result column ="pname" property ="name" /> <result column ="price" property ="price" /> </association > </collection > </resultMap > <select id ="listOrder" resultMap ="orderBean" > select o.id, o.code, oi.id as oiid, oi.num, p.id as pid, p.name as pname, p.price from order_ as o left join orderItem_ as oi on o.id=oi.oid left join product_ as p on oi.pid=p.id; </select > <select id ="getOrder" parameterType ="_int" resultMap ="orderBean" > select o.id, o.code, oi.id as oiid, oi.num, p.id as pid, p.name as pname, p.price from order_ as o left join orderItem_ as oi on o.id=oi.oid left join product_ as p on oi.pid=p.id where o.id=#{id}; </select > </mapper >
添加映射,运行结果如下
订单和产品的关系是通过订单项联系起来的,所以建立关系和删除关系对应的就是创建orderItem_数据和删除其数据。
新建OrderItem.xml,添加增添数据的SQL
1 2 3 4 5 6 7 8 9 10 <?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.ssl.bean" > <insert id ="addOrderItem" parameterType ="OrderItem" > insert into orderItem_ values (null, #{order.id}, #{product.id}, #{num}); </insert > </mapper >
添加映射,在启动类的步骤如下:
查询一个Order
查询一个Product
新建OrderItem,设置Order、Product和num
将OrderItem插入到orderItem_表中 二者关系建立完成。
1 2 3 4 5 6 7 Order order = sqlSession.selectOne("getOrder" , 1 ); Product product = sqlSession.selectOne("getProduct" , 6 ); OrderItem oi = new OrderItem(); oi.setOrder(order); oi.setProduct(product); oi.setNum(300 ); sqlSession.insert("addOrderItem" , oi);
结果如下
删除关系则删除orderItem_的对应数据即可,在OrderItem.xml文件中设置SQL。
6. 总结 使用Mybatis实现增查改删,可以让人更专注于SQL的编写,而不是考虑编写冗余的JDBC代码来操作数据库。
Mybatis其它高阶的使用方法,如c3p0连接池、缓存等等技术需要用到再进行学习。
7. 参考