Mybatis 笔记——动态代理增删改查

Posted Johnny*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis 笔记——动态代理增删改查相关的知识,希望对你有一定的参考价值。

mapper动态代理方式的CRUD

动态代理方式也称为接口开发。是基于以下原理:
约定优于配置。

硬编码方式

Configuration conf = new Configuration();
conf.setName(“myProject”);

配置方式

abc.xml文件中:
myProject

约定

默认值就是myProject

上述优先级是: 约定 >配置方式>硬编码方式
约定的目的是: 省略statement,即根据约定可以直接定位到SQL语句。
要实现该约定则PersonMapper.java接口中方法必须遵守以下规定

  1. 方法名与personMapper.xml文件中的标签id值相同
  2. 方法参数与parameterType类型一致。如果personMapper.xml的标签中没有parameterType,则说明该方法无需方法参数。
  3. 方法的返回值与resultType类型一致。(无论查询结果是一个 还是多个(Person、List),在personMapper.xml标签中的resultType中只写 一个(Person),但是方法中的返回值则需要根据返回结果决定是否使用List;如果没有resultType,则说明方法的返回值为void)

除了以上要实现接口中的方法personMapper.xml中的SQL标签一一对应外,还需:
personMapper.xml的namespace的值要为接口的全类名。这样就可以实现一个接口对应一个mapper文件

匹配的过程

  1. 根据接口全类名==namespace,找到对应的mapper.xml文件
  2. 根据方法名==id值,唯一定位SQL标签。
    在这里插入图片描述

PersonMapper.java 接口

package com.johnny.mapper;

import java.util.List;

import com.johnny.entity.Person;

public interface PersonMapper {
	
	List<Person> selectAllPerson();
	
	Person selectPersonById(int id);
	
	void addPerson(Person per);
	void deletePersonById(int id);
	void updatePerson(Person per);
	

}

PersonMapper.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.johnny.mapper.PersonMapper">  <!-- 该mapper的命名空间要为对应接口的全类名 -->
	
	 <select id="selectPersonById" resultType="com.johnny.entity.Person">
	 	select * from person where id = #{id}
	 </select>
	 
	 <select id="selectAllPerson" resultType="com.johnny.entity.Person">
	 	select * from person 
	 </select>
	 
	 <insert id="addPerson" parameterType="com.johnny.entity.Person">
	 	insert into person(id, age, name)  values( #{id}, #{age}, #{name})
	 </insert>
	 
	 <update id="updatePerson" parameterType ="com.johnny.entity.Person">
	 	update person set name = #{name}, age =#{age} where id = #{id} 
	 </update>
	 
	 <delete id="deletePersonById" parameterType ="int">
	 	delete from person where id=#{id}
	 </delete>
	 
	 
</mapper>

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">
 	<!-- 通过environments 的 default 和 enviroment的id 来指定数据库环境 -->
	 <environment id="development">
	 <!-- transactionManager 事务提交方式
	 	JDBC : 利用JDBC 方式处理事务 (rollback、commit、close) 
	  	MANAGED: 将事务交由其他组件(如spring、jobss)去托管,默认会关闭连接
	  		<property name = "closeConnection" value ="false"/> 来指定不关闭
	  -->
	 <transactionManager type="JDBC"/>
	 	<!-- 数据源类型:
	 		UNPOOLED: 传统的JDBC模式(每次访问数据库需要打开、关闭数据操作,比较消耗性能)
	 		POOLED : 使用数据库连接池方式
	 		JNDI: 从tomcat中获取一个内置的数据库连接池
	 	 -->
		 <dataSource type="POOLED">
		 <!-- 配置数据库信息  -->
		 <property name="driver" value="com.mysql.jdbc.Driver"/>
		 <property name="url" value="jdbc:mysql://localhost:3306/goodsadmin"/>
		 <property name="username" value="用户名"/>
		 <property name="password" value="密码"/>
		 </dataSource>
	 </environment>
 </environments>
 <mappers>
 	<!-- 加载映射文件 -->
 	<mapper resource="com/johnny/mapper/personMapper.xml"/>
 </mappers>
</configuration>

TestMybatis.java

package com.johnny.test;

import java.io.IOException;

import java.io.InputStream;
import java.util.List;

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 com.johnny.entity.Person;
import com.johnny.mapper.PersonMapper;

public class TestMybatis {
	
	public static void selectPersonById() throws IOException {
		//1、加载资源文件:获取mybatis配置文件输入流/MybatisDemo0/src/com/johnny/entity/config.xml
		InputStream in = Resources.getResourceAsStream("config.xml");
		//2、 通过 SqlSessionFactoryBuilder 获得SqlSessionFactory 的实例
		SqlSessionFactory sqlFactory =  new SqlSessionFactoryBuilder().build(in);
		
		//3、获取session对象 --相当于JDBC中的Connection对象
		SqlSession session = sqlFactory.openSession();
		//xml命名空间+sql语句id
		
		PersonMapper personMapper = session.getMapper(PersonMapper.class);
		personMapper.selectPersonById(2);
	}
	
	public static void selectAllPerson() throws IOException {
		InputStream in = Resources.getResourceAsStream("config.xml");
		SqlSessionFactory sqlFactory =  new SqlSessionFactoryBuilder().build(in);
		SqlSession session = sqlFactory.openSession();
		PersonMapper personMapper = session.getMapper(PersonMapper.class);
		List<Person> allPerson = personMapper.selectAllPerson();
		for(Person per: allPerson)
			System.out.println(per);
	}
	
	public static void addPerson() throws IOException {
		InputStream in = Resources.getResourceAsStream("config.xml");
		SqlSessionFactory sqlFactory =  new SqlSessionFactoryBuilder().build(in);
		
		SqlSession session = sqlFactory.openSession();
		PersonMapper personMapper = session.getMapper(PersonMapper.class);
		personMapper.addPerson(new Person(4, "sally", 35));
		session.commit();
		System.out.println("添加成功!");
	}
	
	public static void updatePerson() throws IOException {
		InputStream in = Resources.getResourceAsStream("config.xml");
		SqlSessionFactory sqlFactory =  new SqlSessionFactoryBuilder().build(in);
		SqlSession session = sqlFactory.openSession();
		PersonMapper personMapper = session.getMapper(PersonMapper.class);
		Person per = new Person();
		per.setId(4);
		per.setName("ls");
		per.setAge(28);
		personMapper.updatePerson(per);
		session.commit();
		System.out.println("修改成功!");
	}
		
	
	public static void deletePerson() throws IOException {
		InputStream in = Resources.getResourceAsStream("config.xml");
		SqlSessionFactory sqlFactory =  new SqlSessionFactoryBuilder().build(in);
		
		SqlSession session = sqlFactory.openSession();
		
		PersonMapper personMapper = session.getMapper(PersonMapper.class);
		personMapper.deletePersonById(4);
		//提交事务
		session.commit();
		
		System.out.println("删除成功!");
	}
	

	

	public static void main(String[] args) throws IOException {
		
		selectAllPerson();
//		addPerson();
//		updatePerson();
		deletePerson();
		selectAllPerson();
	
		
		

	}

}

Person.java

package com.johnny.entity;

public class Person {
	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 int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return this.id+"- "+ this.name+"- " +this.age;
	}
	
	public Person() {}
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public Person(int id,String name, int age) {
		this.id = id;
		this.name = name;
		this.age = age;
	}
	private int id;
	private String name;
	private int age;
	

}

优化

数据库配置信息采用动态引入方式:

可以将配置信息 单独放入 db.properties文件中,然后再动态引入

db.properties文件中:
k=v

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/goodsadmin
username=用户名
password=密码

config.xml文件中:
加载数据库配置信息文件
引入之后,使用${key}

<?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>
	<!-- 加载数据库配置信息文件 -->
	<properties resource="dp.properties"/>
	<environments default="development">
		 <environment id="development">
		 <transactionManager type="JDBC"/>

		 	 
			 <dataSource type="POOLED">	 
			 <!-- 配置数据库信息  -->
			 <property name="driver" value="${driver}"/>
			 <property name="url" value="${url}"/>
			 <property name="username" value="${username}"/>
			 <property name="password" value="${password}"/>
			 </dataSource>
		 </environment>
	</environments>
	 <mappers>
	 	<!-- 加载映射文件 -->
	 	<mapper resource="com/johnny/mapper/personMapper.xml"/>
	 </mappers>
</configuration>

批量设置别名

config.xml文件的configuration标签下

<!-- 设置别名 -->
	<typeAliases>
		<!-- 设置单个别名 -->
		<!--  <typeAlias type="com.johnny.entity.Person" alias="person"/> -->
		
		<!-- 批量设置 别名为类名(不带包名),且忽略大小写-->
		<!-- 使用包扫描的方式来定义别名,mybatis会自动扫描指定包下的所有类并将别名装配到上下文中 -->
		<package name="com.johnny.entity" />
	</typeAliases>

之后resultType和parameterType便可直接使用person而无需全类名限定(即com.johnny.entity.Person)

类型处理器(类型转换器)

Mybatis自带类型转化器

Mybatis内置了一些常见类的别名
在这里插入图片描述

自定义Mybatis类型转化器

如果对象的属性类型与表中的字段类型对不上,但是名字对得上。那么mybatis会匹配的上。比如数据字段为sex(int(12) ),Person类属性名也为sex(Boolean)时,即使类型不一致但名字一致,此时mybatis仍可正确匹配上。

要是类型和名字都不匹配则需借助resultMap标签实现一 一映射。

mybatis中似乎有Boolean(java)转Integer(JDBC)的内置转换器

	<select id="selectPersonByIdWithConverter" resultMap="personMapping">
	 	select * from person where id = #{id}
	 </select>	 
	 <resultMap type="person" id="personMapping">
	 	<id  property="id" column="id"/>
	 	<result property="name"  column ="name"/>
	 	<result property="age"  column ="age"/>
	 	<result property="sex"  column ="perSex" />
	 </resultMap>

执行结果仍可正确映射:

1- johnny- 22 - 性别:false
2- weiwei- 98 - 性别:true
3- feng- 25 - 性别:true

若使用自定义的类型转化器
首先要声明实现TypeHandler接口的类,实现转换器有2种选择:
i.实现接口TypeHandler接口
ii.继承BaseTypeHandler

package com.johnny.converter;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

public class BooleanAndNumber extends BaseTypeHandler<Boolean>{
	
	/**
	 * Java 类型- > JDBC类型
	 * @param ps PreparedStatement对象
	 * @param i		数据库表字段所在列
	 * @param parameter  Java类型参数
	 * @param jdbcType  数据库类型
	 */
	public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType)
			throws SQLException {
		if(parameter) ps.setInt(i, 1);
		else ps.setInt(i, 0);
	}
	
	//按列名获取 一般执行该方法
	public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException {
		System.out.println(1112);
		return rs.getInt(columnName)== 1;
	}
	
	//按索引获取
	public Boolean getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		System.out.println(1113);
		return rs.getInt(columnIndex)== 1;
	}

	public Boolean getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		System.out.println(1114);
		return cs.getInt(columnIndex) ==1;
	}


}

其次,配置config.xml

	<!-- 设置自定义类转换器 -->
	<typeHandlers>
		<typeHandler handler="com.johnny.converter.BooleanAndNumber" javaType="Boolean" jdbcType="INTEGER"/>
	</typeHandlers>

最后在需要转换的位置引用:

	<select id="selectPersonByIdWithConverter" resultMap="personMapping">
	 	select * from person where id = #{id}
	 </select>	 
	 <resultMap type="person" id="personMapping">
	 	<id  property="id" column="id"/>
	 	<result property="name"  column ="name"/>
	 	<result property="age"  column ="age"/>
	 	<result property="sex"  column ="perSex"  typeHandler="com.johnny.converter.BooleanAndNumber"/>
	 </resultMap>

resultMap可以实现2个功能:
1.类型转换
2.属性-字段的映射关系

	<select id="selectPersonByIdWithConverter" resultMap="personMapping">
	 	select * from person where id = #{id}
	 </select>	 
	 <resultMap type="person" id="personMa

以上是关于Mybatis 笔记——动态代理增删改查的主要内容,如果未能解决你的问题,请参考以下文章

mybatis中一增删改查

Spring+Struts2+MyBatis+分页(mybatis无代理)增删改查

mybatis 之动态sql 增删改查

mybatis运行原理--执行增删改方法

Mybatis-增删改查

Java Web009 -- MyBatis(入门 & 增删改查 & 动态SQL)