MyBatis(二)动态代理及XML配置
上篇文章中介绍了MyBatis的用法,在Mapper.xml中通过sql语句的唯一标识id去执行对应的sql语句,但是你应该也发现了其中的问题的,就是当你去调用的时候,你必须回到Mapper.xml文件中去复制id,然后又要回去看看参数是什么类型的。
所以MyBatis又提出了动态代理。
我们只需要为MyBatis提供一个Mapper接口:在接口中书写Mapper.xml文件中对应的sql的方法。
但是该Mapper接口中的方法不是随意编写的,必须按照以下几个要求编写:
- 方法名必须与sql语句中的id一致;
- 参数类型必须一样;
- 返回值类型必须一样;
- Mapper.xml中的namespace书写该Mapper接口的全称限定名。
此时的项目结构:
ProductsMapper.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="mapper.ProductsMapper">
<select id="selectProductById" parameterType="int" resultType="pojos.Products">
select * from products where pid = #{pid};
</select>
<!-- like模糊查询-->
<select id="selectProductsLikePname" parameterType="String" resultType="pojos.Products">
select * from products where pname like "%${pname}%";
</select>
<insert id="insertProducts" parameterType="pojos.Products" keyProperty="pid" useGeneratedKeys="true">
insert into products (pname,price,pdate,cid) values (#{pname},#{price},#{pdate},#{cid});
</insert>
<delete id="deleteProductById" parameterType="int">
delete from products where pid = #{pid};
</delete>
<!-- 修改要先获得原来的数据,再进行修改,参数为JavaBean-->
<update id="updateProductById" parameterType="pojos.Products">
update products set pname = #{pname} where pid = #{pid};
</update>
</mapper>
ProductsMapper接口:
package mapper;
import pojos.Products;
import java.util.List;
public interface ProductsMapper {
public Products selectProductById(int pid);
public List<Products> selectProductsLikePname(String pname);
public int insertProducts(Products products);
public int deleteProductById(int pid);
public int updateProductById(Products products);
}
测试:
通过session对象去获取对应的mapper对象,再通过mapper对象去调用方法,此时因为是调用方法,就可以根据idea的提示来书写方法名和方法所需要的参数了。
import mapper.ProductsMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import pojos.Products;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class Test02 {
@Test
public void test01(){
SqlSession session = null;
String resource = "mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
session = new SqlSessionFactoryBuilder().build(inputStream).openSession();
ProductsMapper mapper = session.getMapper(ProductsMapper.class);
//根据主键查询单条数据
Products product = mapper.selectProductById(1);
System.out.println(product);
//模糊查询,结果为多条数据
List<Products> products = mapper.selectProductsLikePname("新疆");
for (Products product1 : products) {
System.out.println(product1);
}
//插入数据
Products p = new Products();
p.setPname("野核桃");
p.setPdate(new Date());
p.setPrice(99);
p.setCid("s002");
int insert = mapper.insertProducts(p);
session.commit();
System.out.println(insert);
System.out.println(p.getPid());
//删除数据
int delete = mapper.deleteProductById(9);
session.commit();
System.out.println(delete);
//修改数据,要先获取原来的数据再进行修改
Products product2 = mapper.selectProductById(8);
product.setPname("芒果");
int update = mapper.updateProductById(product2);
session.commit();
System.out.println(update);
} catch (IOException e) {
if(session != null){
session.rollback();
}
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
}
}
mybatis-config.xml中mappers的四种映射方式
每次只能使用一个
<!-- 根据类路径下的文件路径(相对路径)-->
<mappers>
<mapper resource="mapper/ProductsMapper.xml"/>
</mappers>
<!-- 根据绝对路径(少用)-->
<mappers>
<mapper url="F:\mybatis_code\src\main\resources\mapper\ProductsMapper.xml"/>
</mappers>
<!-- 根据Mapper接口的全称类名-->
<!-- 这种方式要求Mapper接口和Mapper.xml处于同一种目录下-->
<!-- 如:ProductsMapper接口在包com.mapper下,那么必须在resource下新建目录com/mapper,然后放入ProductsMapper.xml-->
<mappers>
<mapper class="mapper.ProductsMapper"/>
</mappers>
<!-- 根据Mapper接口所在的包-->
<!-- 该方式和第三种方式一样:要求Mapper接口和Mapper.xml处于同一种目录下-->
<mappers>
<package name="mapper"/>
</mappers>
mybatis-config.xml配置properties
因为在mybatis.xml文件中需要填写一些与数据库有关的值,如driver、url、username、password,如果直接在配置文件中书写值,后续会不太好修改,所以可以将值放在属性中,在需要的地方使用${key}取值即可。
又可以分为内部属性和外部属性:
<properties>
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
</properties>
<!-- 外部属性配置,引入外部的属性文件 -->
<properties resource="jdbc.properties"/>
可以同时配置,但是当出现同名时,会优先使用外部属性。
<properties resource="jdbc.properties">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
</properties>
mybatis-config.xml配置typeAliases
parameterType和resultType的数据类型为JavaBean时,需要书写类的全称限定名,但是写来写去的就很烦,所以mybatis提供了typeAliases配置:
<typeAliases>
<typeAlias type="pojos.Products" alias="products"/>
</typeAliases>
这样就不需要书写类的全称限定名,而是可以使用简单的alias别名了。
但是如果JavaBean很多的时候,这样一个个去配置的话就太麻烦了,所以MyBatis又贴心的给我们提供了另外一种方式:
将某个包下的所有的JavaBean的别名配置成类名小写字母开头:
<typeAliases>
<package name="pojos"/>
</typeAliases>
可以配置多个包。
问题也就来了,不同包下的类是可以同名的,如果不同包下有同名的类,产生重名的话就会有冲突,所以这个时候我们就要使用@Aliase注解:
@Alias("别名")
并且还需要注意的是,MyBatis已经存在了一些别名,我们取的时候不能和它们冲突(可以查看MyBatis文档有哪些已经存在的)