工程目录结构查看:
面向接口开发的过程:
写一个接口,方法照着xml配置文件中的方法写,public+返回值对应resultType+方法名称对应id+参数对应parameterType,然后session.getMapper(OrderMapper.class),其中mpper底层会创建OrderMapper的实现类,通过jdk动态代理方式实现,断点调试可以看到$ProxyN这个动态代理实现类对象,通过接口全局限定名cn.tedu.order.pojo.OrderMapper的路径(即包名.类/接口名称),找到相对应的命名空间,就找到映射文件OrderMapepr.xml,解析映射文件,找到所有SQL语句。因为调用的是接口的find方法,就找到映射文件中的find标签,找到标签就找到sql语句,利用Executor执行sql语句,返回记录集ResultSet,获取这个结果集,遍历这个结果集,获取每条记录,从记录中获取每个字段,例如id,获取到id对应值,通过xml中配置的返回值,就拿到pojo对象,调用setld,底层调用反射中回调类的setld(id),pojo的属性有值了,遍历所有的字段,pojo这一个对象就都有值了,遍历所有的结果集,创建多个pojo对象,最终设置完所有的属性值,最终再放入到list集合中
尽管是面向接口开发,但是mapper.xml中的方法配置仍然需要手动编写,config.xml和mapper.xml两个文件都不能少,否则报org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.swliu.person.pojo.PersonMapper.find ......
1.数据库文件mybatisdb2.sql
(1)cmd执行(本身GBK):
mysql -uroot -prootswliu
SET NAMES GBK;
(2)mysql客户端工具Navicat等(本身UTF8):
SET NAMES UTF8;-- 可以省略
CREATE DATABASE IF NOT EXISTS `mybatisdb2` DEFAULT CHARACTER SET utf8;
USE `mybatisdb2`;
DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(20) DEFAULT NULL,
`school` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
insert into `person`(`id`,`user_name`,`school`) values (1,'tony','北大'),(2,'hellen','清华');
select * from `person`;
Delete删除所有的数据,但是不更新一些配置,比如自增id的值不会被清;
Truncate删除所有的数据,把特有的配置也还原,比如自增id也从0开始。
2. 测试类TestInterface.java
package person;
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 org.junit.Before;
import org.junit.Test;
import com.swliu.person.pojo.Person;
import com.swliu.person.pojo.PersonMapper;
//面向接口式开发
public class TestInterface {
//初始化工厂对象
private SqlSessionFactory factory;
//初始化
@Before
public void init() throws IOException{
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(is);
}
@Test //调用接口的方式,没有实现类
public void find(){
SqlSession session = factory.openSession();
//调用getMapper方法,参数是接口
//调用接口方式,$ProxyN底层使用jdk动态代理技术,Mybatis底层创建了实现类
PersonMapper mapper = session.getMapper(PersonMapper.class);
Person p = new Person(); //参数
List<Person> personList = mapper.find(p);
for(Person x: personList){
System.out.println(x);
}
}
}
测试类TestPerson.java
package person;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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 org.junit.Before;
import org.junit.Test;
import com.swliu.person.pojo.Person;
//原始xml配置方式的开发
public class TestPerson {
private SqlSessionFactory factory;
@Before //在每个方法执行前执行
public void init() throws IOException{
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(is);
}
@Test
public void find(){
SqlSession session = factory.openSession();
String ns = "com.swliu.person.pojo.PersonMapper.find";
//参数,mybatis如果创建pojo,属性未设置它的值null(使用包装类型的好处)
Person p = new Person();
//p.setUserName("tony");
p.setSchool("北大");
List<Person> personList = session.selectList(ns, p);
for(Person x :personList){
System.out.println(x);
}
}
@Test
public void update(){
SqlSession session = factory.openSession();
String ns = "com.swliu.person.pojo.PersonMapper.update";
//参数,mybatis如果创建pojo,属性未设置它的值null
Person p = new Person();
p.setId(1);
p.setUserName("");
//p.setUserName("ruse");
//p.setSchool("");
//p.setSchool("哈佛");
session.update(ns,p);
session.commit();
}
@Test
public void delete(){
SqlSession session = factory.openSession();
String ns = "com.swliu.person.pojo.PersonMapper.delete";
//参数map
Map<String,Object> p = new HashMap<String,Object>();
p.put("ids", new Integer[]{13,14}); //key一个,value数组
session.delete(ns,p);
session.commit();
}
@Test
public void deleteArray(){
SqlSession session = factory.openSession();
String ns = "com.swliu.person.pojo.PersonMapper.deleteArray";
//参数array
session.delete(ns, new Integer[]{15,16});
session.commit();
}
@Test
public void deleteList(){
SqlSession session = factory.openSession();
String ns = "com.swliu.person.pojo.PersonMapper.deleteList";
//参数list
List<Integer> list = new ArrayList<Integer>();
Collections.addAll(list, 17,18);
session.delete(ns, list);
session.commit();
}
}
3.配置事务、数据源、映射文件、全局配置文件 sqlMapConfig.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>
<!--
核心配置文件中标签是有顺序性的:
元素类型为 "configuration" 的内容必须匹配
properties
settings
typeAliases
typeHandlers
objectFactory
objectWrapperFactory
plugins
environments
databaseIdProvider
mappers
-->
<!-- 加载属性文件 -->
<properties resource="jdbc.properties"/>
<!-- 全局配置,mapUnderscoreToCamelCase 下划线和驼峰规则自动映射 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 简化类,起别名 -->
<typeAliases>
<typeAlias type="com.swliu.person.pojo.Person" alias="Person"/>
</typeAliases>
<!-- 配置环境、事务、数据源、映射文件 -->
<environments default="test">
<environment id="test">
<!-- 支持两种类型:JDBC/MANAGE -->
<transactionManager type="JDBC"/>
<!-- 数据源:POOLED/UNPOOLED/JNDI -->
<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>
<!-- 告诉mybatis映射文件存在 -->
<mappers>
<!--
Mybatis早期提供方法selectList/selectOne这种方式不是面向对象思考方式,
推出接口式开发(接口式开发无需xml配置访问)
开发步骤:
(1)创建一个接口(Map接口有实现类HashMap),无需写实现类
(2)sqlSession对象来调用这个接口
注意路径:
(1)保证接口文件放在和映射文件同一目录(约定)
(2)命名空间指向映射文件的目录
(3)在全局配置文件中告诉mybatis接口存在,不能同时存在接口和xml方式
jdk动态代理实现,动态根据接口来创建实现类
接口实际上最终调用的还是xml中的方法
org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(statement, parameter)
在实际开发Mybatis程序时,大多数情况使用的都是接口方式,少数必须使用原始xml配置方式关联对象ResultMap!!!
-->
<!-- 全局限定名=包名.类/接口名称 -->
<mapper class="com.swliu.person.pojo.PersonMapper"/>
<!-- Mybatis早期提供方法selectList/selectOne的方式:-->
<mapper resource="com/swliu/person/pojo/PersonMapper.xml"/>
</mappers>
</configuration>
mappers严格按照顺序执行:先class,后resource
jdbc.properties数据源配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatisdb2?characterEncoding=utf8
username=root
password=rootswliu
4.配置映射文件的命名空间(java包): 包的路径.映射文件的名称 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.swliu.person.pojo.PersonMapper">
<!-- 第三种改进:使用核心配置文件全局配置,mapUnderscoreToCamelCase下划线和驼峰规则自动映射,无需字段另起别名和resultMap映射 -->
<select id="find" parameterType="Person" resultType="Person">
SELECT id,user_name,school FROM person
where 1=1
<if test="userName != null">and user_name = #{userName}</if>
<if test="school != null"> and school = #{school}</if>
</select>
<!-- 第二种改进:带参查询 -->
<select id="find3" parameterType="Person" resultMap="personResultMap">
SELECT id,user_name,school FROM person
where 1=1
<if test="userName != null">and user_name = #{userName}</if>
<if test="school != null"> and school = #{school}</if>
</select>
<!-- 构建复杂映射关系,id唯一,type返回值放入哪个pojo -->
<resultMap type="Person" id="personResultMap">
<!-- 主键,property pojo的属性, column数据库表的字段 -->
<id property="id" column="id"/>
<!-- 普通字段,起到了映射规则:数据库结果集字段user_name,
内部会自动调用person.setUserName方法
-->
<result property="userName" column="user_name"/>
<result property="school" column="school"/>
</resultMap>
<!-- 第一种:使用where标签,会自动去掉最前面的and/or,字段使用别名以便找到对应的实体类属性 -->
<!--
<select id="find2" parameterType="Person" resultType="Person">
SELECT id,user_name userName,school FROM person
<where>
<if test="userName != null">user_name = #{userName}</if>
<if test="school != null"> and school = #{school}</if>
</where>
</select>
-->
<!-- 修改:set标签会自动去掉最后面的逗号"," -->
<update id="update" parameterType="Person">
UPDATE person
<set>
<if test="userName != null and userName !='' ">user_name=#{userName},</if>
<if test="school != null and userName !='' ">school=#{school},</if>
</set>
WHERE id=#{id}
</update>
<!-- 批量删除改进 map:k(ids) v(3,4,5) (更灵活更常用)-->
<delete id="delete" parameterType="map">
DELETE FROM person WHERE id
<foreach collection="ids" item="id" separator="," open="in (" close=")" >
#{id}
</foreach>
</delete>
<!-- 批量删除 map:k(ids) v(3,4,5) (格式不好看)
<delete id="delete" parameterType="map">
DELETE FROM person WHERE id in (
<foreach collection="ids" item="id" separator="," >
#{id}
</foreach>
)
</delete>
-->
<!-- 批量删除数组元素的类型(不灵活不常用)-->
<delete id="deleteArray" parameterType="int">
DELETE FROM person WHERE id
<foreach collection="array" item="id" separator="," open="in (" close=")">
#{id}
</foreach>
</delete>
<!-- 批量删除list元素的类型(不灵活不常用)-->
<delete id="deleteList" parameterType="int">
DELETE FROM person WHERE id
<foreach collection="list" item="id" separator="," open="in (" close=")">
#{id}
</foreach>
</delete>
</mapper>
5.javaBean类Person.java
package com.swliu.person.pojo;
public class Person {
private Integer id;
private String userName;
private String school;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
@Override
public String toString() {
return "Person [id=" + id + ", userName=" + userName + ", school=" + school + "]";
}
}
6.log4j.properties日志打印
log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
7.pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.swliu</groupId>
<artifactId>mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<argLine>-Dfile.encoding=UTF-8</argLine>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<!--
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<forkMode>once</forkMode>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
</plugins>
</build>
-->
</project>
8.接口 PersonMapper.java
package com.swliu.person.pojo;
import java.util.List;
//必须是一个接口
public interface PersonMapper {
//写一个查询方法
//<select id="find" parameterType="Person" resultType="Person">
public List<Person> find(Person p);
}
打印信息: 略