Fork me on GitHub

JavaEE Day05 Mybatis

Day05 Mybatis


软件开发三层架构

sun提出分层开发(经典三层)

表示层

与用户进行交互的组件和容器组成。

实现:Servlet
框架:action/web

业务逻辑层

由业务处理组件构成。

实现:Service/biz
框架:srping framwork

数据持久层

实现与数据库直接交互。

实现:Jdbc dao
框架:mybatis/hibernate

什么是框架

将重复性的,繁琐的内容封装起来一套程序,是开发人员能够将更多的精力放在业务分析和理解上;

框架的好处

  1. 简化开发(配置)
  2. 屏蔽细节
  3. 提高开发效率

传统jdbc的不足

  1. 驱动注册和连接获取硬编码问题(配置文件)
  2. 赋值和结果封装繁琐(反射 orm)
  3. 频繁的打开和释放连接消耗资源(连接池)

什么是mybatis

Mybatis官网

  1. mybatis是一款有效的持久层框架,

  2. mybatis需要关注sql,输入参数和输出结果的映射

  3. mybatis是一个orm框架

    orm:对象关系映射,解决面向对象编程蘑菇型和关系型数据库模型之间的映射问题。

入门案例

准备工作

需要jar:mysql驱动包,mybatis相关jar

  1. apache项目:ibatis
  2. 移植google code:mybatis
  3. github:开源软件托管平台
  4. 下载:https://github.com/mybatis/mybatis-3/releases
  5. 如果需要查看mybatis的debug信息,则需要log4j-1.2.17.jar(一般位于mybatis目录的lib目录下,是mybatis的日志程序),另外将log4j.properties配置文件导入到配置中即可;

log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

创建实体类

在src下创建pojo程序包,在程序包中创建对应的实体类,

package pojo;

public class UserInfo {
    private int uid;
    private String username;
    private String password;

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "uid=" + uid +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

编写java项目

两种配置文件

  1. 创建在项目目录下创建源码目录(ecplise中,是source folder,idea中创建普通目录,然后在modules中修改)

  2. 全局配置:四个参数(连接池) 事务管理

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- xml描述文件:dtd/schema(约束标签) -->
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <!--加载外部属性文件-->
        <properties resource="java.properties">
            <!--<property name="" value=""/>-->
        </properties>
        <!-- 类型别名 -->
        <typeAliases>
            <!-- 单个类型别名 -->
            <!--<typeAlias type="pojo.UserInfo" alias="UserInfo"></typeAlias>-->
            <!-- 批量级别 :别名就是类型,不区分大小写-->
            <package name="pojo"/>
        </typeAliases>
        <!-- 环境 context :复数
            mysql、oracle、db2
            本地环境  预上线平台  线上环境
            default: 默认使用环境
        -->
        <environments default="development">
            <!-- 环境:id:唯一标识 -->
            <environment id="development">
                <!-- 事务管理器 :JDBC -->
                <transactionManager type="JDBC"/>
                <!-- 数据源:连接池(存储的连接) dpcp/c3p0/droid/jdbcTemplate -->
                <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="UserMapper.xml"/>
        </mappers>
    </configuration>
    
  3. 映射配置:定制化sql,输入参数和输出结果映射。

    <?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:命名空间(字符串)
    	隔离sql
     -->
    <mapper namespace="adhs">
        <!-- <insert id=""></insert>
        <update id=""></update>
        <delete id=""></delete> -->
    
        <!-- 根据uid查询userinfo的对象
            一个标签代表一个Statement对象
                #{}:代表占位符
                    关键字:输入参数类型
                        简单类型:可任意
                        对象:属性名称
                id:标签的唯一标识
                parameterType:输入参数的类型(可选)
                resultType:输出结果类型
         -->
        <select id="selectUser" resultType="UserInfo">
          select * from userinfo where uid = #{uid}
        </select>
    </mapper>
    

读取配置运行测试

  1. SqlSession:面向开发者的接口。提供发送sql命令的方法
  2. SqlSessionFactory:session工厂,创建和管理session对象。

package test;

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 pojo.UserInfo;

import java.io.IOException;
import java.io.Reader;

public class Test {
    public static void main(String[] args) throws IOException{
        // 读取配置文件
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
        // 发送定制化sql
        SqlSession session = ssf.openSession();
        UserInfo info = session.selectOne("adhs.selectUser", 1);
        System.out.println(info);
        session.close();
    }
}

增删改查案例

mybaties中 默认将autocommit关闭了,所以插入,修改和删除的操作,默认都是不成功的,为了开启autocommit,有两种方法:

  1. 直接在opensssion中设置true属性(查看源码,idea快捷点 ctrl+alt+B 查看所有的继承类;)
  2. 直接手工事务提交;

注意: 如果传入的参数是对象类,那么#{}里面的参数,就是属性名;

UserMapper.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:命名空间(字符串)
	隔离sql
 -->
<mapper namespace="adhs">
    <!-- <insert id=""></insert>
    <update id=""></update>
    <delete id=""></delete> -->

    <!-- 根据uid查询userinfo的对象
        一个标签代表一个Statement对象
            #{}:代表占位符
                关键字:输入参数类型
                    简单类型:可任意
                    对象:属性名称
            id:标签的唯一标识
            parameterType:输入参数的类型(可选)
            resultType:输出结果类型(单个结果的类型)
     -->
    <select id="selectUser" resultType="UserInfo">
      select * from userinfo where uid = #{uid}
    </select>
    <!-- 查询所有  -->
    <select id="selectAll" resultType="userinfo">
        select * from userinfo;
    </select>
    <!-- 模糊查询 String
        ${}:表示连接"+"
            关键字:与输入参数类型有关
                简单类型:value
                对象类型:属性名称

     -->
    <select id="selectLikeName" resultType="userinfo">
        select * from userinfo where username like "%${value}%"
    </select>
    <!-- 插入数据 输入参数是对象,因此在调用#{}时,写属性名称-->
    <insert id="insert">
        insert into userinfo(username,password) values(#{username},#{password})
    </insert>
    <update id="update">
        update userinfo set username=#{username},password=#{password} where uid=#{uid}
    </update>
    <delete id="delete">
        delete from userinfo where uid=#{uid}
    </delete>
</mapper>

测试代码:


package test;

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 pojo.UserInfo;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class Test {
    public static void main(String[] args) throws IOException{
        // 读取配置文件
        Reader reader = Resources.getResourceAsReader("mybatis.xml");

        SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
        // 发送定制化sql
        SqlSession session = ssf.openSession();
        // 自动事务提交
//        SqlSession session = ssf.openSession(true);
       /* UserInfo info = session.selectOne("adhs.selectUser", 1);
        System.out.println(info);*/
//        List<UserInfo> users = session.selectList("adhs.selectAll");
        /*List<UserInfo> users = session.selectList("adhs.selectLikeName", "s");
        System.out.println(users.toString());*/
        UserInfo info = new UserInfo();
        info.setUid(7);
        info.setUsername("zl");
        info.setPassword("567");
//        int rows = session.insert("adhs.insert", info);
//        int rows = session.update("adhs.update",info);
        int rows = session.delete("adhs.delete",7);
        // 手动事务提交
        session.commit();
        System.out.println(rows);
        session.close();
    }
}

mapper代理实现dao的开发

mapper的接口+mapper映射

要求:

  1. mapper接口和mapper映射同包同名(注册映射方便)
  2. mapper映射文件的namespace和接口的完全限定名保持一致
  3. 标签的id和方法的名称保持一致
  4. 标签的输入参数类型和方法的参数类型一致
  5. 标签的输出结果类型(单个类型)和方法的返回值类型一致;

目录结构

.
├─config 
│	├─java.properties
│	├─log4j.properties
│	└─mybatis.xml
├─lib
│	├─log4j-1.2.17.jar
│	├─mybatis-3.4.6.jar
│	└─mysql-connector-java-5.1.45-bin.jar
├─bin
└─src
    ├─mapper
    │	├─UserMapper.java
	│	└─UserMapper.xml
    ├─pojo
    │	└─UserInfo.java
    └─test
    	└─Test.java

mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- xml描述文件:dtd/schema(约束标签) -->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--加载java属性文件-->
    <properties resource="java.properties"></properties>
    <!-- 类型别名 -->
    <typeAliases>
        <package name="pojo"/>
    </typeAliases>
    <!-- 配置环境 -->
    <environments default="dev">
        <!-- 环境:id:唯一标识 -->
        <environment id="dev">
            <!-- 事务管理器 :JDBC -->
            <transactionManager type="JDBC"/>
            <!-- 数据源:连接池(存储的连接) dpcp/c3p0/droid/jdbcTemplate -->
            <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接口和映射文件必须同包同名 -->
        <package name="mapper"/>
    </mappers>

</configuration>

UserMapper.java

package mapper;

import pojo.UserInfo;

import java.util.List;

public interface UserMapper {

    List<UserInfo> queryAll();

    UserInfo queryById(int uid);

}

UserMapper.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.UserMapper">
    <select id="queryAll" resultType="userinfo" >
        select * from userinfo
    </select>
    <select id="queryById" resultType="userinfo">
        select * from userinfo where uid = #{uid};
    </select>
</mapper>

使用注解

也就是不用写UserMapper.xml,修改UserMapper.java即可

package mapper;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Update;
import pojo.UserInfo;
import java.util.*;

import org.apache.ibatis.annotations.Select;

public interface UserMapper {
	
	@Select("select * from userinfo")
	List<UserInfo> queryAll();
	
	@Select("select * from userinfo where uid=#{uid}")
	UserInfo queryById(int uid);

	@Insert("insert into userinfo(username,password) values(#{username},#{password})")
	int insert(UserInfo info);
	
	@Update("update userinfo set username=#{username},password=#{passwrod} where uid=#{uid}")
	int update(UserInfo info);

	@Delete("delete from userinfo where uid=#{uid} ")
    int delete(int uid);

}

高级映射

一对多问题

resultType特点:

  1. 结果集 中的字段名称和类属性名称完全一致,此时将映射成功。
  2. 结果集中的字段名称和类属性名称部分一致,部分映射成功-可以在sql中起别名解决;
  3. 结果集中的字段名称和雷属性的名称完全不一致,此时不会创建对象

emp实体

package pojo;

import java.math.BigDecimal;
import java.sql.Date;

public class Emp {

    private int empno;
    private String ename;
    private String job;
    private int mgr;
    private java.sql.Date hiredate;
    private BigDecimal sal;
    private BigDecimal comm;
    private int deptno;
    private Dept dept;

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public int getEmpno() {
        return empno;
    }

    public void setEmpno(int empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public int getMgr() {
        return mgr;
    }

    public void setMgr(int mgr) {
        this.mgr = mgr;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public BigDecimal getSal() {
        return sal;
    }

    public void setSal(BigDecimal sal) {
        this.sal = sal;
    }

    public BigDecimal getComm() {
        return comm;
    }

    public void setComm(BigDecimal comm) {
        this.comm = comm;
    }

    public int getDeptno() {
        return deptno;
    }

    public void setDeptno(int deptno) {
        this.deptno = deptno;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", mgr=" + mgr +
                ", hiredate=" + hiredate +
                ", sal=" + sal +
                ", comm=" + comm +
                ", deptno=" + deptno +
                ", dept=" + dept +
                '}';
    }
}

dept实体

package pojo;

import java.util.List;

public class Dept {

    private int deptno;
    private String dname;
    private String loc;
    private List<Emp> emps;

    public int getDeptno() {
        return deptno;
    }

    public void setDeptno(int deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    public List<Emp> getEmps() {
        return emps;
    }

    public void setEmps(List<Emp> emps) {
        this.emps = emps;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptno=" + deptno +
                ", dname='" + dname + '\'' +
                ", loc='" + loc + '\'' +
                ", emps=" + emps +
                '}';
    }
}

resultMap(orm)

使用collection标签, ofType属性;

查询dept表中所有员工和所在部门

DeptMapper.java

package mapper;

import pojo.Dept;

import java.util.List;

public interface DeptMapper {
    List<Dept> findDeptAndEmps();

}

DeptMapper.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.DeptMapper">
    <!--id:唯一标识    type:封装类型  -->
    <resultMap type="dept" id="deptMap">
        <!--  主键字段的映射  property:属性名称   column:结果集中字段名称-->
        <id property="deptno" column="deptno"/>
        <result column="dname" property="dname"/>
        <result column="loc" property="loc"/>
        <!-- 将表中数据封装到集合中   ofType:集合中的类型 -->
        <collection property="emps" ofType="emp" column="deptno">
            <id property="empno" column="empno"/>
            <result column="ename" property="ename"/>
            <result column="job" property="job"/>
            <result column="mgr" property="mgr"/>
            <result column="hiredate" property="hiredate"/>
            <result column="sal" property="sal"/>
            <result column="comm" property="comm"/>
            <result column="deptno" property="deptno"/>
        </collection>
    </resultMap>
    <select id="findDeptAndEmps" resultMap="deptMap">
		select * from dept left join emp on dept.deptno = emp.deptno
	</select>

</mapper>

一对一问题

使用association 标签,javaType属性

EmpMapper.java

package mapper;

import pojo.Emp;

import java.util.List;

public interface EmpMapper {
    List<Emp> findEmpAndDept();
}

EmpMapper.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.EmpMapper">
    <!-- id: 唯一标识, type:封装的类型-->
    <resultMap id="empMap" type="emp">
        <!-- 主键字段的映射 property:属性名称 column:结果集中的字段名称 -->
        <id property="empno" column="empno"/>
        <result column="ename" property="ename"/>
        <result column="job" property="job"/>
        <result column="mgr" property="mgr"/>
        <result column="hiredate" property="hiredate"/>
        <result column="sal" property="sal"/>
        <result column="comm" property="comm"/>
        <result column="deptno" property="deptno"/>
        <!--将结果封装到对象中-->
        <association property="dept" column="deptno" javaType="dept">
            <id property="deptno" column="deptno"/>
            <result column="dname" property="dname"/>
            <result column="loc" property="loc"/>
        </association>


    </resultMap>
    <select id="findEmpAndDept" resultMap="empMap" >
        select * from emp left join dept
            on dept.deptno = emp.deptno
    </select>
</mapper>

测试代码

package test;

import mapper.DeptMapper;
import mapper.EmpMapper;
import mapper.UserMapper;
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 java.io.IOException;
import java.io.Reader;

public class Test {
    public static void main(String[] args) {
    
        Reader reader = null;
        try {
        
            reader = Resources.getResourceAsReader("mybatis.xml");
            SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
            SqlSession session = ssf.openSession();
            
			// DeptMapper mapper = session.getMapper(DeptMapper.class);
			// System.out.println(mapper.findDeptAndEmps());
			
            EmpMapper mapper = session.getMapper(EmpMapper.class);
            System.out.println(mapper.findEmpAndDept());
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

posted @ 2018-10-28 10:25  耳_东  阅读(83)  评论(0)    收藏  举报