Mybatis笔记
Mybatis
MyBatis 是支持定制化 SQL、存储过程以及高级映射的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
1.使用mysql数据库(MySQLWorkbench):
建库建表,填充数据。
2.创建实体类Category
public class Category {
private int id;
private String name;
}
3.配置文件mybatis-config.xml(src目录下创建)
下面可以配置多个元素节点,而每个节点可以配置两个东西,一个是事务管理器配置,另一个是数据源配置。
<?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.bean" />
</typeAliases>
<!-- 设置别名,自动扫描com.bean下类型, 在Category.xml使用resultType时不用写全com.bean.Category,直接用Category -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" /><!-- 使用jdbc事务管理 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8" />
<!-- 数据库名,编码格式 -->
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/bean/Category.xml" />
</mappers><!-- 映射Category.xml -->
</configuration>
4.配置Category.xml(com.bean目录)
<?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.bean">
<select id="listCategory" resultType="Category"><!-- 因为myBatis-config.xml直接写Category -->
select * from category_
</select>
</mapper>
5.测试类TestMybatis
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);
// 通过配置文件"mybatis-config.xml"得到SQLSessionFactory(创建SqlSession对象的工厂)
SqlSession session = sqlSessionFactory.openSession();
// 通过SQLSessionFactory得到Session
List<Category> cs = session.selectList("listCategory");
// 通过session的selectList方法,调用sql语句listCategory。
for (Category c : cs) {
System.out.println(c.getName());
}
}
}
原理:
1. 应用程序找mybatis要数据
2. mybatis从数据库中请求数据
- 通过mybatis-config.xml 定位数据库
- 通过Category.xml执行对应的select语句
- 基于Catgory.xml把返回的数据库记录封装在Category对象中
- 把多个Category对象装在一个Category集合中
- 返回一个Category集合
基本的增删改查:
实体类(映射数据库表)–>Mybatis-config.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.bean">
<insert id="addCategory" parameterType="Category">
insert into category_(name) values (#{name})
</insert>
<delete id="deleteCategory" parameterType="Category">
delete from category_ where id= #{id}
</delete>
<select id="getCategory" parameterType="_int" resultType="Category">
select * from category_ where id=#{id}
</select>
<update id="updateCategory" parameterType="Category">
update category_ set name=#{name} where id=#{id}
</update>
<select id="listCategory" resultType="Category"><!-- 因为myBatis-config.xml直接写Category -->
select * from category_
</select>
</mapper>
parameterType的用法:
1.基本数据类型,如输入参数只有一个,其数据类型可以是基本的数据类型,也可以是自己定的类类型。包括int,String,Integer,Date,如下:
(1)根据id进行相应的删除:
<delete id="deleteById" parameterType="Integer">
(2)添加员工:
<insert id="addEmp" parameterType="com.pojo.Employee">
2.复杂数据类型:包含java实体类,map。
另外MyBatis还提供了一个使用注解来参与多个参数的方式。这种方式需要在接口的参数上添加@Param注解此处要注意的是,由于该方法需要传入多个参数,在进行MyBatis配置时,没有办法同时配置多个参数,另外MyBatis还提供了一个使用注解来参数多个参数的方式。这种方式需要在接口的参数上添加@Param注解注意,以下两种写法是完全相同的。
但使用的时候要使用第一种类型
Userlogin(@Param(value =“name”)Stringname,
@Param(value =“password”)String password); //用户登录(String name,String password);
配置如下:
<select id =“login”resultType =“com.pojo.User”>
select * from us where name =#{name} and password =# {密码}
</ select>
<选择ID = “getWinLogByEventId”参数类型= “java.lang.Long中” >结果映射= “BaseResultMap”> > 选择<包括REFID = “基础_列_列表”/>从取胜_登录其中EVENTID =# { _ parameter,jdbcType = BIGINT} </ select >
3.获取参数中的值:
1.基本数据类型:#{参数}获取参数中的值 2.复杂数据类型:#{属性名}, map中则是#{key}
测试类:
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);
// 通过配置文件"mybatis-config.xml"得到SQLSessionFactory(创建SqlSession对象的工厂)
SqlSession session = sqlSessionFactory.openSession();
// 通过SQLSessionFactory得到Session
Category c = new Category();
// 增加
c.setName("addCategory");
session.insert("addCategory", c);
// 删除
c.setId(6);
session.delete("deleteCategory", c);
// 查询
c = session.selectOne("getCategory", 3);
System.out.println(c.getName());
// 更改
c = session.selectOne("getCategory", 4);
c.setName("修改了姓名");
session.update("updateCategory", c);
// 遍历
listAll(session);
session.commit();
session.close();
}
private static void listAll(SqlSession session) {
// TODO Auto-generated method stub
List<Category> cs = session.selectList("listCategory");
// 通过session的selectList方法,调用sql语句listCategory。
for (Category c : cs) {
System.out.println(c.getName());
}
}
}
模糊查询:
实体类配置文件:
<select id="listCategoryByName" parameterType="String"
resultType="Category">
select * from category_ where name like concat('%',#{0},'%')
<! - 如果是oracle,写法是 - >
<! - select * from category_ where'name'like '%'||#{0} ||'%' - >
</ select>
测试代码:
List <Category> cs = session.selectList(“listCategoryByName”,“cat”);
for(Category c1:cs){
System.out.println(c1.getName());
}
**多条件查询:**结合前面的模糊查询,多一个id多少的条件1。
<select id="listCategoryByIdAndName" parameterType="map" resultType="Category">
select * from category_ where id> #{id} and name like concat('%',#{name},'%')
</select>
因为是多个参数,而selectList方法又只接受一个参数对象,所以需要把多个参数放在Map里面,然后把这个Map对象作为参数传递进去
Map <String,Object> params = new HashMap < >();
params.put(“id”,0);
params.put(“name”,“cat”);
List <Category> cs = session.selectList(“listCategoryByIdAndName”,params);
for(Category c1:cs){
System.out.println(c1.getName());
}
1.一对多:(分类–产品)
1、数据库建表,填数据。
2、新建一个普通的一个pojo Product实体类
public class Product {
private int id;
private String name;
private float price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Product [id=" + id + ",name=" + name + ",price=" + price;
}
}
3.修改Category实体类
在Category类中增加:
List<Product> products;
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
4.修改Category.xml
通过left join关联查询,对Category和Product表进行关联查询。
与前面学习的有所区别,这里不是用的resultType, 而是resultMap,通过resultMap把数据取出来放在对应的 对象属性里
注: Category的id 字段 和Product的id字段同名,Mybatis不知道谁是谁的,所以需要通过取别名cid,pid来区分。
name字段同理。
<mapper namespace="com.bean">
<resultMap type="Category" id="categoryBean"> <id column="cid" property="id"
/> <result column="cname" property="name" />
<!-- 一对多关系 -->
<!-- property:指集合属性的值,ofType:指集合中元素的类型 -->
<collection property="products" ofType="Product">
<id column="pid" property="id" />
<result column="pname" property="name" />
<result column="price" property="price" />
</collection>
</resultMap>
<!-- left join关联查询 产品分类和产品表 -->
<select id="listCategory" resultMap="categoryBean">
select c.*,p.*,c.id 'cid',p.id 'pid',c.name 'cname',p.name 'pname' from category_ c left join product_ p on c.id=p.cid </select>
</mapper>
5、测试
// 一对多关系
public static void listCategory(SqlSession session) {
List<Category> cs = session.selectList("listCategory");
for (Category category : cs) {
System.out.println(category);
List<Product> ps = category.getProducts();
for (Product product : ps) {
System.out.println("/t" + product);
}
}
}
2.多对一关系(产品–>分类)
1.修改实体类为Product增加category属性
private Category category;
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
2.新建Product.xml
提供Product.xml,通过listProduct配置关联查询的sql语句。
然后通过resultMap ,进行字段和属性的对应。
使用association(关联) 进行多对一关系关联,指定表字段名称与对象属性名称的一一对应关系
注: Category的id 字段 和Product的id字段同名,Mybatis不知道谁是谁的,所以需要通过取别名cid,pid来区分。
name字段同理。
<?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.bean">
<resultMap type="Product" id="productBean">
<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 c.*,p.*,c.id 'cid',p.id 'pid' ,c.name 'cname',p.name 'pname' from
category_ c left join product_ p on c.id=p.cid
</select>
</mapper>
3.在mybatis-config.xml中增加对于Product.xml的映射
<mapper resource="com/bean/Product.xml" />
4.测试
// 多对一关系
public static void listProduct(SqlSession session) {
List<Product> ps = session.selectList("listProduct");
for (Product product : ps) {
System.out.println(product + "\t对应的分类是\t" + product.getCategory());
}
}
3.多对多关系
以订单Order和产品Product为例:
一张订单***里可以包含***多种产品
一种产品 可以出现在***多张订单***里
这就是多对多关系,为了维系多对多关系,必须要一个中间表。 在这里我们使用订单项(OrderItem)表来作为中间表。
- 查询多对多关系
- 建立多对多关系
- 删除多对多关系
1.数据库建表填充数据。
新建order_表,同理新建order_item_表
填充数据:
2.新建实体类Order和OrderItem
自动生成getset方法。
public class Order {
private int id;
private String code;
List<OrderItem> orderItems;
}
public class OrderItem {
private int id;
private int number;
private Order order;
private Product product;
}
3.配置映射文件Product、Order、OrderItem。
Product.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.bean">
<resultMap type="Product" id="productBean">
<id column="pid" property="id" />
<result column="pname" property="name" />
<result column="price" property="price" />
<!-- 多对一的关系 -->
<!-- property: 指的是属性名称, javaType:指的是属性的类型 -->
<association property="category" javaType="Category">
<id column="cid" property="id" />
<result column="cname" property="name" />
</association>
</resultMap>
<select id="listProduct" resultMap="productBean">
select c.*,p.*,c.id
'cid',p.id 'pid' ,c.name 'cname',p.name 'pname' from
category_ c left
join product_ p on c.id=p.cid
</select>
<select id="getProduct" resultMap="productBean">
select c.*, p.*, c.id 'cid', p.id 'pid', c.name 'cname', p.name 'pname'
from category_ c
left join product_ p on c.id = p.cid
where p.id = #{id}
</select>
</mapper>
Order.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.bean">
<resultMap type="Order" id="orderBean">
<id column="oid" property="id" />
<result column="code" property="code" />
<collection property="orderItems" ofType="orderItem">
<id column=" oiid" property="id" />
<result column="number" property="number" />
<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.*,p.*,oi.*, o.id
'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join
order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
</select>
<select id="getOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
where o.id = #{id}
</select>
</mapper>
OrderItem.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.bean">
<insert id="addOrderItem" parameterType="OrderItem">
insert into order_item_
values(null,#{order.id},#{product.id},#{number})
</insert>
<insert id="deleteOrderItem" parameterType="OrderItem">
delete from order_item_
where oid = #{order.id} and pid = #{product.id}
</insert>
</mapper>
修改mybatis-config.xml
增加映射文件
<mapper resource="com/bean/Order.xml" />
<mapper resource="com/bean/OrderItem.xml" />
4.建立关系
(1).查询
Test
private static void listOrder(SqlSession session) {
List<Order> orders = session.selectList("listOrder");
for (Order order : orders) {
System.out.println(order.getCode());
List<OrderItem> oItems = order.getOrderItems();
for (OrderItem orderItem : oItems) {
System.out.format("\t%s\t%f\t%d%n", orderItem.getProduct().getName(), orderItem.getProduct().getPrice(),
orderItem.getNumber());
}
}
}
(2).增加关系
// 建立关系(插入数据)
// 首先通过id分别获取Order和Product对象,接着就新建一个OrderItem对象,set order和product
// 还有数量,最后用"addOrderItem"对应的sql语句插入.
private static void addOrderItem(SqlSession session) {
Order order = session.selectOne("getOrder", 1);
Product product = session.selectOne("getProduct", 2);
OrderItem orderItem = new OrderItem();
orderItem.setProduct(product);
orderItem.setOrder(order);
orderItem.setNumber(200);
session.insert("addOrderItem", orderItem);
}
(3).删除关系
// 删除关系(就是删掉OrderItem记录)
// 同上通过对应的Order和Product的id进行删除
private static void deleteOrderItem(SqlSession session) {
Order order = session.selectOne("getOrder", 1);
Product product = session.selectOne("getProduct", 2);
OrderItem orderItem = new OrderItem();
orderItem.setProduct(product);
orderItem.setOrder(order);
session.delete("deleteOrderItem", orderItem);
}
(4).修改
多对多不存在修改关系的做法,就是删除旧的,然后新增一条即达到修改的效果。
动态sql------if标签
以查询Product表为例:
1.Product.xml配置文件
使用模糊查询的时候可能会用到不同的字段,如果查询一次使用一条sql语句,会变得难以维护,就能使用Mybatis的动态sql----if标签
;如果没有传入参数那么就是查询所有,这样就可以一条语句应付多种情况。
<mapper namespace="com.bean">
<select id="listProductByName" resultType="Product">
select * from product_
<if test="name!=null">
where name like concat('%',#{name},'%')
</if>
</select>
</mapper>
2.test
// 查询Product使用模糊查询
private static void listProductByName(SqlSession session) {
Map<String, Object> params = new HashMap<>();
params.put("name", "b");//"b"通过动态输入灵活查询
List<Product> ps = session.selectList("listProductByName", params);
for (Product product : ps) {
System.out.println(product);
}
}
动态sql------where标签
1.修改Product.xml配置文件
当出现多条件查询的时候不能愉快的直接使用
select * from product_ where name like concat(’%’,#{name},’%’) and price > #{price}会出现name为空price不为空的语句错误;这时候就使用where标签。
如果任何条件都不成立,那么就在sql语句里就不会出现where关键字
如果有任何条件成立,会自动去掉多出来的 and 或者 or。
<select id="listProductByName" resultType="Product">
select * from product_
<where>
<if test="name!=null">
and name like concat('%',#{name},'%')
</if>
<if test="price!=null and price!=0">
and price > #{price}
</if>
</where>
</select>
2.test
// 多条件查询
private static void listProductByNameAndPrice(SqlSession session) {
Map<String, Object> params = new HashMap<>();
params.put("name", "b");// 这时params值为不为空都可以正常运行
params.put("price", "2");
List<Product> ps = session.selectList("listProductByName", params);
for (Product product : ps) {
System.out.println(product);
}
}
动态sql------set标签
1.修改Product.xml配置文件
与where标签类似的,在update语句里也会碰到多个字段相关的问题。 在这种情况下,就可以使用set标签:
<update id="updateProduct" parameterType="Product">
update product_
<set>
<if test="name!=null">name=#{name},</if>
<if test="price!=null">price=#{price}</if>
</set>
where id=#{id}
</update>
2.test
// 修改Product
private static void updateProductById(SqlSession session) {
Product p=new Product(5,"product zz",9.99f);
session.update("updateProduct", p);
}
动态sql------trim标签
trim 用来定制想要的功能,比如where标签就可以用
<trim prefix="WHERE" prefixOverrides="AND|OR">
</trim>
替换
set标签就可以用
<trim prefix="SET" suffixOverrides=",">
</trim>
替换。
<select id="listProductByName" resultType="Product">
select * from product_
<trim prefix="WHERE" prefixOverrides="AND|OR"><!-- =where -->
<if test="name!=null">
and name like concat('%',#{name},'%')
</if>
<if test="price!=null and price!=0">
and price > #{price}
</if>
</trim>
</select>
<update id="updateProduct" parameterType="Product">
update product_
<trim prefix="SET" suffixOverrides=","><!-- set -->
<if test="name!=null">name=#{name},</if>
<if test="price!=null">price=#{price}</if>
</trim>
where id=#{id}
</update>
效果和where和set一样。
动态sql------choose标签
1.修改Product.xml配置文件
<!-- Mybatis里面没有else标签,但是可以使用when otherwise标签来达到这样的效果。 -->
<select id="productList" resultType="Product">
select * from product_
<where>
<choose>
<when test="name!=null">and name like concat('%',#{name},'%')</when>
<when test="price!=null and price!=0">and price > #{price}</when>
<otherwise>
and id>1
</otherwise>
<!-- 起作用是: 提供了任何条件,就进行条件查询,否则就使用id>1这个条件。 -->
</choose>
</where>
</select>
2.test
private static void productList(SqlSession session) {
Map<String, Object> params = new HashMap<>();
List<Product> ps = session.selectList("productList", params);
for (Product product : ps) {
System.out.println(product);
}
}
动态sql------foreach标签
1.修改Product.xml配置文件
<!-- foreach标签通常用于in 这样的语法里,比如查询id是1,2,3的数据 -->
<select id="listProductForeach" resultType="Product">
SELECT * FROM product_
WHERE ID in
<foreach item="item" index="index" collection="list" open="("
separator="," close=")">
#{item}
</foreach>
</select>
2.test
private static void productListForeach(SqlSession session) {
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
List<Product> ps = session.selectList("listProductForeach", ids);
for (Product product : ps) {
System.out.println(product);
}
}
动态sql------bind标签
1.修改Product.xml配置文件
<!-- bind标签就像是再做一次字符串拼接,方便后续使用 -->
<!-- 如下,在模糊查询的基础上,把模糊查询改为bind标签。 -->
<select id="listProductBind" resultType="Product">
<bind name="likename" value="'%'+name+'%'" />
select * from product_ where name like #{likename}
</select>
2.test
private static void listProductBind(SqlSession session) {
Map<String, String> params = new HashMap<>();
params.put("name", "product");
List<Product> ps = session.selectList("listProductBind", params);
for (Product product : ps) {
System.out.println(product);
}
}