一、增删改查

接下来我们通过映射文件的操作来实现mybatis对数据库的增删改操作
1.EmployeeMapper.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" >
<!-- namespace命名空间特殊作用: 如果使用mapper动态代理方法,这里就需要配置mapper接口地址-->
<mapper namespace="dao.EmployeeMapper">
    <resultMap id="BaseResultMap" type="Bean.Student" >
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="name" property="name" jdbcType="VARCHAR" />
    </resultMap>
    
<!--插入方法-->
    <insert id="addEmp" parameterType="Bean.Employee" >
        insert into tbl_employee(last_name,email,gender)
        values (#{lastName},#{email},#{gender})
    </insert>

    <!--更新方法-->
    <update id="updateEmp" parameterType="Bean.Employee">
        update tbl_employee
        set last_name=#{lastName},email=#{email},gender=#{gender}
        where id=#{id}
    </update>
    
    <!--删除方法-->
    <delete id="deleteEmpById">
        delete from tbl_employee where id=#{id}
    </delete>

</mapper>

2.dao层接口

public interface EmployeeMapper {

    public void addEmp (Employee employee);

    public boolean updateEmp(Employee employee);

    public void deleteEmpById(Integer id);
}

3.将映射文件注册到全局配置文件中:

<mappers>
        <mapper resource="EmployeeMapper.xml"/>
</mappers>

4.测试类:
插入方法:

@Test
    public void test03() throws IOException {
        try {
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

            //插入
            Employee employee = new Employee(null, "tom", "tom@qq.com", "0");
            mapper.addEmp(employee);
            System.out.println(employee.getId());

            //手动提交
            sqlSession.commit();
        } catch (IOException e){
            e.printStackTrace();
        }
    }

由于是获取主键自增,所以插入时将id置为null,mybatis会自动生成后去的id号。

运行结果:

mysql geometry mybatis Java 映射_sql

修改方法:

@Test
    public void test03() throws IOException {
        try {
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

            //修改
            Employee employee = new Employee(13, "jack", "jack@qq.com", "0");
            boolean updateEmp = mapper.updateEmp(employee);
            System.out.println(updateEmp);
            
            //手动提交
            sqlSession.commit();
        } catch (IOException e){
            e.printStackTrace();
        }
    }

运行结果:

mysql geometry mybatis Java 映射_xml_02

删除方法:

@Test
    public void test03() throws IOException {
        try {
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

            //删除
            mapper.deleteEmpById(13);
            //手动提交
            sqlSession.commit();
        } catch (IOException e){
            e.printStackTrace();
        }
    }

运行结果:

mysql geometry mybatis Java 映射_sql_03

切记手动提交: sqlSession.commit();

二、注解式编程

1.编写dao层接口方法:

import Bean.Student;
import org.apache.ibatis.annotations.Select;

public interface StudentMapperAnnotation {
    @Select("select * from student where id = #{id}")
    Student getUserById(Integer id);
}

2.将dao层接口注册到全局配置文件中:

<mappers>
        <mapper class="dao.StudentMapperAnnotation"/>
</mappers>

3.测试类:

@Test
    public void test1() throws IOException {
        try {
            /**
             * 通过Resource获取mybatis配置流
             */
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            /**
             * 获取SqlSessionFactory实例
             */
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            /**
             * 获取SqlSession实例
             */
            SqlSession sqlSession = sqlSessionFactory.openSession();
            /**
             * 通过反射获取dao实例
             */
            StudentMapperAnnotation mapper = sqlSession.getMapper(StudentMapperAnnotation.class);

            Student student = mapper.getUserById(1);
            //System.out.println(student.getClass());
            System.out.println(student);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

运行结果:

mysql geometry mybatis Java 映射_主键_04

三、获取主键自增

mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys
useGeneratedKeys = “true” :使用自增主键获取主键值
keyProperty :指定对应的主键属性,就是mybatis获取到主键值以后,将这个值分封装给javaBean的那个属性

<insert id="addEmp" parameterType="Bean.Employee" useGeneratedKeys="true" keyProperty="id">
        insert into tbl_employee(last_name,email,gender)
        values (#{lastName},#{email},#{gender})
</insert>

四、参数处理

1.多个参数处理:

单个参数:mybatis不会做特殊处理
#{参数名}:取出参数值

多个参数:mybatis会做特殊处理
多个参数会被封装成一个map
key:param1…paramN,或者参数的索引也可以
value:传入的参数值
#{}就是从map中获取指定的key值;

出现的 异常:

org.apache.ibatis.binding.BindingException:
Parameter 'id' not found. Available parameters are [1, 0, param1, param2]

操作:
方法:public Employee getEmpByIdAndLastName(Integer id,String lastName);
取值:#{id},#{lastName}

命名参数:明确指定封装参数时map的key

POJO:
如果多个参数正好是我们业务逻辑的数据模型,可以直接传入pojo;
#{属性名}: 取出传入的pojo的属性值

Map:
多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,可以传入map
#{key}:取出map中对应的值

TO:
如果多个参数不是业务模型中的数据,但也经常使用,推荐来编写一个TO(Transfer Object)数据传输对象

Page{
 int index;
 int size;
 }

思考:
public Employee getEmp(@Param(“id”)Integer id,String lastName);
取值:id==>#{id/param1} lastName==>#{param2}

public Employee getEmp(Integer id,@Param(“e”)Employee emp);
取值: id==>#{param1} lastName ==>#{param2.lastName/e.lastName}

###注意:如果是Collection(List,set)类型或是数组,
也会特殊处理,也是把传入的list或者数组封装在map中
public Employee getEmp(List ids);
取值:取出第一个id的值 : #{ids[0]}

测试:
dao层接口:

import Bean.Employee;
import org.apache.ibatis.annotations.Param;

public interface EmployeeMapper {

    public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName") String lastName);
}

映射文件:

<select id="getEmpByIdAndLastName" resultType="Bean.Employee">
        select  * from tbl_employee where id =#{id} and last_name=#{lastName}
    </select>

测试类:

@Test
    public void test04() throws IOException {
        try {
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

            Employee employee = mapper.getEmpByIdAndLastName(1,"GINO");
            System.out.println(employee);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

mysql geometry mybatis Java 映射_主键_05

2.源码 :myabtis如何处理参数

public Object getNamedParams(Object[] args) {
        int paramCount = this.names.size();
        //1.参数为null直接返回
        if (args != null && paramCount != 0) {
            //2.如果只有一个元素,并且没有Param注解;args[0] :单个参数直接返回
            if (!this.hasParamAnnotation && paramCount == 1) {
                return args[(Integer)this.names.firstKey()];
            //3.多个元素或Param标注
            } else {
                Map<String, Object> param = new ParamMap();
                int i = 0;
                //4.遍历names集合  {0=id,1=lastName}
                for(Iterator i$ = this.names.entrySet().iterator(); i$.hasNext(); ++i) {
                    Entry<Integer, String> entry = (Entry)i$.next();
                    //names集合的value作为key; names集合的key作为取值参考args[0]:args[1"Tom"]
                    //eg:{id:args[0]:1,lastName=args[1]:Tom}
                    param.put(entry.getValue(), args[(Integer)entry.getKey()]);
                    //add generic param names (param1,param2,…)
                    //额外的将每一个参数也保存到map中,是新的key:param1…paramN
                    String genericParamName = "param" + String.valueOf(i + 1);
                    if (!this.names.containsValue(genericParamName)) {
                        param.put(genericParamName, args[(Integer)entry.getKey()]);
                    }
                }
                return param;
            }
        } else {
            return null;
        }
    }

总结:参数多的时候会封装map:为了不混乱,我们可以使用@Param来制定封装时使用的key

#{key}就可以取出,ap中的值;
 (@Param(“id”)Integer id,@Param(“lastName”)String lastName);
 ParamNameResolver解析参数封map过程:
//1.names:{0=id,1=lastName};构造器的时候就确定好了


1.获取每个标了param注解的参数的@Param的值:id lastName:赋值给name;
2.每次解析一个参数给map中保存信息:(key:参数索引,Value:name的值)
name的值:
标注了param注解:注解的值
没有标注:

1.全局配置:useActualParamName(jdk1.8):name=参数名
 2.name=map.size():相当于当前元素的索引
 {0=id, 1=lastName,2=2}

3.参数值得获取(#{}和${}的区别):

#{}:可以获取map中的值或者pojo对象属性的值
${}:可以获取map中的值或者pojo对象属性的值
区别:#{}:是以预编译的形式,将参数设置到sql语句中:PreparedStatement,防止sql注入
KaTeX parse error: Expected 'EOF', got '#' at position 46: … 大多情况下去参数值都应该使用#̲{} 原生jdbc不…{}进行取值
比如分表、排序:按照年份分表拆表
select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name} ${order}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
            try {
                return method.invoke(this, args);
            } catch (Throwable var5) {
                throw ExceptionUtil.unwrapThrowable(var5);
            }
        } else {
            MapperMethod mapperMethod = this.cachedMapperMethod(method);
            return mapperMethod.execute(this.sqlSession, args);
        }
    }