Mybatis 框架(二)—— Mapper 接口开发规范、映射文件的配置(1)

一、使用 Mybatis 实现增删改查

1、Mapper 接口开发规范

(1)Mapper.xml 文件中的 namespace 与 mapper 接口的类路径相同。

  • Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
  • Mapper接口方法的参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
  • Mapper接口方法的返回值类型和mapper.xml中定义的每个sql的resultType的类型相同

(2)在执行某些数据库操作时,在sql语句中需要动态的赋予参数,参数的来源是数据层接口中方法的参数,在映射文件中使用这些参数有两种写法#{}${}

  • #{}表示一个占位符号,通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。
  • ${}表示拼接sql串,通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换,${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是value。
    基本上能使用#{}就不要使用${}避免 sql 注入

二、映射文件的配置(1)

1、新增数据时获取主键值

在某些场景中,我们需要使用新增的这一行数据的主键值,例如:在新增订单的操作中,我们首先需要新增一行订单表数据,然后再新增订单详情数据,而订单详情中有一个字段用来记录订单详情所属的订单编号,这种情况下我们必须获取到订单数据的主键值,在 jdbc 中我们可以通过 getGeneratedKey 这个函数来获取新增的主键值数据,那么在 mybatis 中该如何处理呢?
在映射文件的insert标签和update标签中可以使用两个属性 useGeneratedKeys 和 keyProperty 来完成这个工作。

	<!-- 新增 -->
<insert id="save" parameterType="Products" useGeneratedKeys="true" keyProperty="p_id">
	insert into products(p_name,p_price,p_count) values(#{p_name},#{p_price},#{p_count})
</insert>
  • useGeneratedKeys 设置为 true 表示当前数据库使用自增长的方式生成主键值,在操作完毕以后会使用该自增长的值
  • keyProperty 则表示在新增完毕以后生成的主键值保存在参数的那个属性中,比如说id属性
    最后执行新增以后就可以从新增的用户对象中取出id的值
Products products = new Products();
products.setP_name("M416");
products.setP_price(100);
products.setP_count(20);
mapper.save(products);
session.commit();
//返回新增数据的主键值
int keyId = products.getP_id()
System.out.println(keyID);

2、打印sql语句执行过程

使用 mybatis 的日志,可以打印sql语句的执行过程,只需要在核心配置文件中添加标签

<settings>
      <setting name="logImpl" value="STDOUT_LOGGING" /> 
</settings>

3、在mybatis核心配置文件中指定类型的别名

在映射文件中的标签中经常需要用到类型的名称,例如 parameterType 和 resultType,虽然直接写类型的全限定名称完全可以,但是类的限定名称往往特别复杂,写起来非常麻烦,mybatis 同时还支持以别名的方式来定义参数类型或者返回值类型。对于java中的常见类型mybatis已经为其提供了对应的别名,见下表

别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
map Map

如果想为项目中的自定义实体类型定义别名就需要在mybatis的核心配置文件的根标签中使用typeAliases标签。

<typeAliases>
	<!-- 定义单个的别名 -->
	<typeAlias type="com.woniu.entity.User" alias="User"/>
	<!-- 批量定义别名:将自动以该包中的所有类的类名作为别名,不区分大小写 -->
	<package name="com.woniu.entity"/>
</typeAliases>

在核心配置文件中注意标签的书写位置:

顺序 标签
1 properties
2 settings
3 typeAliases
4 typeHandlers
5 objectFactory
6 objectWrapperFactory
7 reflectorFactory
8 plugins
9 environments
10 databaseIdProvider
11 mappers

4、使用 sql 标签定义可重用的 sql 语句

在映射文件中使用 sql 标签定义 sql 语句片段,在需要使用该sql语句片段的标签中使用 include 标签引入定义好的 sql 语句。

<sql id="columns">p_id,p_name,p_price</sql>
<select id="select" resultType="Products>
	<include refid="columns"></include>
</select>

5、使用 foreach 标签实现多行新增

某些数据库是支持多行新增的,例如 mysql,mysql 中多行新增的语法是:

insert  into 表 values(第一行的数据),(第二行的数据),....以此类推

根据语法结构我们不难发现,要实现多行新增需要在values后重复书写每一行的数据内容,mybatis 提供了 foreach 标签可以在执行新增时根据参数,循环拼接sql语句,以此我们可以实现多行新增。
(1)多行新增的参数应该定义为集合类型

public void insertMore(List<Products> list);

(2)映射文件中的标签写法:

<!-- 多行新增 -->
<insert id="insertMore" parameterType="list">
	insert into products values
	<foreach collection="list" item="products" separator=",">
		(null,#{products.p_name},#{products.p_price},#{products.p_count})
	</foreach>
</insert>

foreach 标签属性说明:

  • collection:需要循环的集合名称,必须写作 list 或者 collection,如果参数类型是Set集合,则必须写作collection。
  • item:foreach循环时的对象名称,可以使用该名称获取每一个对象中的属性值。
  • separator:分隔符,每循环一次在末尾自动添加的分隔符(除了最后一次循环)。

6、动态 sql 查询

动态 sql 主要用于动态的添加查询条件,动态添加查询条件可以使用 if 标签和 where 标签,用法如下:
(1)单独使用 if 标签:

<!-- if标签 -->
<select id="selectIf" resultType="Products" >
	select
	<include refid="columns"></include>
	from products
	<if test="p_name != null and '' != p_name">
		and p_name = #{p_name}
	</if>
</select>

单独使用 if 标签时,test 属性中书写条件,可以直接使用参数中的属性名称参与判断,如果条件成立则会拼接if标签中的 sql 语句,否则不会,在一个 select 中可以使用多个 if 标签来动态添加多个条件。

(2)where 标签和 if 标签配合
where 标签只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。

<!-- 动态sql查询使用where和if标签 -->
<select id="selectWhere" resultType="Products" parameterType="Products">
       select <include refid="columns"></include> from products
       <where>
        <if test="p_name != null and '' != p_name">
            and p_name = #{p_name}
        </if>
       </where>
</select>

三 、Mybatis 示例 Demo1

(1)实体类
① 商品实体类

public class Products {
	private int p_id;
	private String p_name;
	private double p_price;
	private int p_count;
	private String p_class;
	private String p_attribute;
	private int p_typeid;
	//省略set、get、toString方法
}

② 动态追加条件实体类

public class ProductsExample {
	private List<String> examples = new ArrayList<String>();
	
	public List<String> getExamples() {
		return examples;
	}
	public void setExamples(List<String> examples) {
		this.examples = examples;
	}
	public void eq(String name, Object value) {
		String example = " and " + name + "=" +"'"+value+"'";
		System.out.println(example);
		examples.add(example);
	}
	public void gt(String name, Object value) {
		String example = " and " + name + ">"+value;
		System.out.println(example);
		examples.add(example);
	}
}

(2)数据层 Mapper 层
① 数据层的 SelectMapper 类,定义各类方法

public interface SelectMapper {
	//查询所有数据
	public List<Products> select();
	//新增数据
	public void save(Products products);
	//删除数据
	public void delete(Products products);
	//修改数据
	public void update(Products products);
	//模糊查询数据
	public List<Products> selectLike(String p_name);
	//分页查询数据
	public List<Products> selectLimit(Map<String, Object> map);
	//聚合函数count查询
	public int selectCount();
	//多表联合查询
	public List<Products> selectUnion();
	//多行新增
	public void insertMore(List<Products> list);
	//使用if标签动态sql查询
	public List<Products> selectIf(Products products);
	//foreach标签定义查询多个条件
	public List<Products> selectExample(List<String> list);
	//根据单个字符串数据动态追加条件进行排序
	public List<Products> order(String column);
	//使用where和if标签动态sql查询
	public List<Products> selectWhere(Products products);
}

② 数据层与 SelectMapper 类对应的 SelectMapper.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.mybatis.demo1.dao.SelectMapper">
   <!-- sql标签定义可重用的sql语句 -->
   <sql id="columns">p_id,p_name,p_price,p_count,p_class,p_attribute</sql>
   
   <!-- 查询所有 -->
   <select id="select" resultType="Products" >
       select <include refid="columns"></include> from products
   </select>
   <!-- 模糊查询 -->
   <select id="selectLike" resultType="Products" parameterType="string">
       select <include refid="columns"></include> from products where p_name like #{p_name}
   </select>
   <!-- 分页查询 -->
   <select id="selectLimit" resultType="Products" parameterType="map">
       select <include refid="columns"></include> from products limit #{startIndex}, #{selectNum}
   </select>
   <!-- 多表联合查询 -->
   <select id="selectUnion" resultType="map">
       select p_name,p_price,p_count,lt_name as tname from products as p inner join ltype as t on p.p_typeid = t.lt_id
   </select>
   <!-- 聚合函数count查询 -->
   <select id="selectCount" resultType="int">
       select count(p_id) from products
   </select>
 
   <!-- 新增 -->
   <insert id="save" parameterType="Products">
       insert into products values(null,#{p_name},#{p_price},#{p_count},#{p_class},#{p_attribute},#{p_typeid})
   </insert>
   <!-- 删除 -->
   <insert id="delete" parameterType="Products" >
       delete from products where p_id = #{p_id}
   </insert>
   <!-- 修改 -->
   <insert id="update" parameterType="Products" >
       update products set p_price = #{p_price}, p_count = ${p_count} where p_id = ${p_id}
   </insert>
   
   <!-- 多行新增 -->
   <insert id="insertMore" parameterType="list">
        insert into products values
        <foreach collection="list" item="products" separator=",">
            (null,#{products.p_name},#{products.p_price},#{products.p_count},#{products.p_class},#{products.p_attribute},#{products.p_typeid})
        </foreach>
   </insert>
   
   <select id="selectExample" resultType="products" parameterType="list">
        select <include refid="columns"></include> from products where 1 = 1
        <foreach collection="list" item="example">
            ${example}
        </foreach>
   </select>
   
   <!-- 动态sql查询使用if标签 -->
   <select id="selectIf" resultType="Products" parameterType="Products">
        select <include refid="columns"></include> from products where 1 = 1
        <if test="p_name != null and '' != p_name">
            and p_name = #{p_name}
        </if>
        <if test="p_price != 0">
            and p_price > #{p_price}
        </if>
        <if test="p_count != 0">
            and p_count > #{p_count}
        </if>
   </select>
   
   <!-- 根据单个字符串数据动态追加条件 -->
   <select id="order" resultType="Products" parameterType="string">
        select <include refid="columns"></include> from products
        <if test="_parameter != null">
            order by ${_parameter}
        </if>
   </select>
   
   <!-- 动态sql查询使用where和if标签 -->
   <select id="selectWhere" resultType="Products" parameterType="Products">
        select <include refid="columns"></include> from products
        <where>
	        <if test="p_name != null and '' != p_name">
	            and p_name = #{p_name}
	        </if>
	        <if test="p_price != 0">
	            and p_price > #{p_price}
	        </if>
	        <if test="p_count != 0">
	            and p_count > #{p_count}
	        </if>
        </where>
   </select>
</mapper>

(3)Test 类

public class Test {
	public static void main(String[] args) {
		try {
			//加载配置文件获取输入流对象
			InputStream is = Resources.getResourceAsStream("Mybatis1.xml");
			//通过输入流对象中的信息获取SqlSessionFactory
			SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
			//通过SqlSessionFactory获取SqlSession对象
			SqlSession session = factory.openSession();
			
			SelectMapper mapper = session.getMapper(SelectMapper.class);
			//新增数据
			Products products = new Products();
			products.setP_name("M416");
			products.setP_price(100);
			products.setP_count(20);
			products.setP_class("武器");
			products.setP_attribute("突击步枪");
			products.setP_typeid(1);
			mapper.save(products);
			session.commit();
			//返回新增数据的主键值
			System.out.println(products.getP_id());
			
			//删除数据
			Products products = new Products();
			products.setP_id(213);
			mapper.delete(products);
			session.commit();
			
			//修改数据
			Products products = new Products();
			products.setP_id(213);
			products.setP_price(111);
			products.setP_count(234);
			mapper.update(products);
			session.commit();
			
			//查询所有数据
			List<Products> list = mapper.select();
			System.out.println(list);
			
			//分页查询数据
			int startIndex = 5;	//设置起始查询页
			int selectNum = 10;	//设置每页显示数量
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("startIndex", (startIndex - 1) * selectNum);
			map.put("selectNum", selectNum);
			List<Products> list = mapper.selectLimit(map);
			System.out.println(list);
			
			//模糊查询数据
			String p_name = "%M%";
			List<Products> list = mapper.selectLike(p_name);
			System.out.println(list);
			
			//多表联合查询
			List<Products> list = mapper.selectUnion();
			session.commit();
			System.out.println(list);
			
			//聚合函数count查询
			int count = mapper.selectCount();
			session.commit();
			System.out.println(count);
			
			//多行新增
			List<Products> list = new ArrayList<Products>();
			Products products1 = new Products();
			products1.setP_name("M416");
			products1.setP_price(100);
			products1.setP_count(20);
			products1.setP_class("武器");
			products1.setP_attribute("突击步枪");
			products1.setP_typeid(1);
			
			Products products2 = new Products();
			products2.setP_name("M416");
			products2.setP_price(100);
			products2.setP_count(20);
			products2.setP_class("武器");
			products2.setP_attribute("突击步枪");
			products2.setP_typeid(1);
			list.add(products1);
			list.add(products2);
			mapper.insertMore(list);
			session.commit();
			
			//foreach标签定义查询多个条件
			ProductsExample example = new ProductsExample();
			example.eq("p_name", "M416");
			example.gt("p_price", "1000");
			List<Products> list = mapper.selectExample(example.getExamples());
			System.out.println(list);
			
			//使用if标签动态sql查询
			Products products = new Products();
			products.setP_name("M416");
			products.setP_price(1000);
			products.setP_count(100);
			List<Products> list = mapper.selectIf(products);
			System.out.println(list);
			
			//根据单个字符串数据动态追加条件进行排序
			List<Products> list = mapper.order("p_price");
			System.out.println(list);
			
			//使用where和if标签动态sql查询
			Products products = new Products();
			products.setP_name("M416");
			products.setP_price(1000);
			products.setP_count(100);
			List<Products> list = mapper.selectWhere(products);
			System.out.println(list);
			
			session.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
发布了75 篇原创文章 · 获赞 10 · 访问量 2867

猜你喜欢

转载自blog.csdn.net/baidu_27414099/article/details/104440442