十二、MyBatis框架(1)

1 Mybatis概述

1.1 认识框架

什么是框架
框架就是一个架子,表演节目,舞台已经搭建好,表演什么节目,看自己的需求了。

框架是一个半成品,对于Java语言来说,框架就是封装了别人的代码。在框架的基础上我们在进一步开发,拿来主义。
框架解决什么问题

解决的是技术整合问题。软件开发环境和规模都很大,不可能任何一个项目的代码都从零开始,此时就需要一个非常优秀的框架把基础技术整合完毕,我们在他的基础上进一步开发。提高性能,易扩展,易维护,最终提高整个团队的开发效率。

什么时候使用框架
企业级大型项目开发

怎么使用框架
Java的框架是具有一些共性

  • 导入jar包
  • 框架运行细节定义,也就是编写配置文件(xml)
  • 调用框架中的api

1.2 MyBatis框架

  • Mybatis原本是Apache软件基金会的一个开源项目叫做iBatis,2010年这个项目由Apache迁移到了google code管理才改名为Mybatis,2013年又迁移到了GitHub。

  • Mybatis是一个优秀的持久层框架(Dao层框架),它是对JDBC的封装,使得开发者只需要关注Sql语句(业务本身)即可,无需开发者处理加载驱动、获取连接、创建Statement等繁琐的过程。

  • Mybatis最大的特点是把Sql语句写在XML配置文件当中。而且Mybatis执行完Sql语句之后可以以对象形式返回(POJO/POJO集合等)。

  • Mybatis是一个实现了ORM思想的持久层框架。

  • ORM:Object/Relation Mapping 对象/关系映射。

  • ORM思想:将数据库中的关系数据表映射为JAVA中的对象,把对数据表的操作转换为对对象的操作,实现面向对象编程。因此ORM的目的是使得开发人员以面向对象的思想来操作数据库。

    比如:原来insert使用的是insert into…,如果使用实现了ORM思想的持久层框架,就可以在Java程序中直接调用api,比如insert(User),达到操作对象即操作数据库的效果。Hibernate框架是一个全自动的ORM持久层框架,只需要编写POJO,在xml中定义好Pojo属性和数据表字段的映射/对应关系,就可以在java中实现类似 insert(User)的操作。Sql语句都不用写。但是因为性能等问题,市场占有率越来越低

    Mybatis框架是一个半自动的ORM持久层框架,也可以在Java中实现类似 insert(User)的操作最终操作数据库,但是需要我们自己写Sql语句。Mybatis是目前比较流行的Dao层框架。

1.3 MyBatis快速入门

原生的JDBC案例

 *  原始的JDBC,对数据表user查询,结果集存储List集合
 *
 *  原始程序的问题: 维护性差,扩展性差,出现问题,修改源码
 *    代码量大
 *    频繁连接,释放数据库资源,降低系统性能
 *       解决办法: 引出连接池,Apache DBUtils
 *
 *    数据库驱动类 ,连接四大信息
 *       解决办法: 写配置文件,读取
 *
 *    SQL语句硬编码,SQL语句写死了
 *    SQL语句中的?占位符
 *      解决办法:写配置文件,读取
 *
 *    封装数据表结果集代码,硬编码
 *
 *    框架: 最基本的代码,整合起来
 *    连接数据库,执行SQL语句,封装结果集整合
 *    只要提供: SQL语句,写xml中
public class JdbcDemo {
    public static void main(String[] args) throws Exception{
        //注册驱动程序
        Class.forName("com.mysql.jdbc.Driver");
        //获取连接
        Connection con =
                DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis","root","root");
        //SQL语句执行对象
        PreparedStatement pst = con.prepareStatement("select * from user ");
        //执行查询,返回结果集
        ResultSet rs =  pst.executeQuery();
        List<User> userList = new ArrayList<User>();
        while (rs.next()){
            User user = new User();
            //取出表中的数据, rs对象的方法getXXX()
            user.setId( rs.getInt("id") );
            user.setUsername( rs.getString("username"));
            user.setSex(rs.getString("sex"));
            user.setBirthday( rs.getDate("birthday") );
            user.setAddress( rs.getString("address"));
            userList.add(user);
        }
        for(User user : userList){
            System.out.println(user);
        }

        rs.close();
        pst.close();
        con.close();
    }
}

使用MyBatis框架

  • 所有的Dao层框架都是以接口的形式给我们提供增删改查的API
  • 我们今天自定义Mybatis框架只完成一个API接口:selectList

在这里插入图片描述

 * MyBatis框架的快速入门
 * 		SqlMapConfig.xml 配置的是连接信息
 * 		UserMapper.xml 配置的是数据表user的SQL语句

SqlMapConfig.xml:(配置了连接信息、事务、连接池、映射数据库表操作的配置文件UserMapper.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"  默认,值=development  开发环境

        environment 运行环境,配置一个
         id="development"  id唯一性的属性 值=id="development"  开发环境
         id="product"  生产环境
         id="test"     测试环境
    -->

    <environments default="development">
        <environment id="development">
            <!--
                 transactionManager 事务管理配置
                 type="JDBC"  使用的是最原始的JDBC的事务处理机制
                 type="MANAGERED" 不管理事务
            -->
            <transactionManager type="JDBC" />
            <!--
                dataSource 配置数据源,连接池
                type="POOLED" 使用连接池
                MyBatis自带连接池  (type=""UNPOOLED)
            -->
            <dataSource type="POOLED">
                <!--配置的是,数据库连接四大信息-->
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf8" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>

        <environment id="produce">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatisProduce?characterEncoding=utf8" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>

        <environment id="test">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatisTest?characterEncoding=utf8" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>



    </environments>

    <!--
      配置的是映射关系  ORM Java对象和数据表
    -->
    <mappers>
        <!--
               单独的映射关系
               resource资源,映射文件的路径
               UserMapper.xml 配置的是数据表user的SQL语句
        -->
        <mapper resource="UserMapper.xml" />

        <!--<mapper resource="StudentMapper.xml"/>-->
    </mappers>
</configuration>    

UserMapper.xml:(配置了查询语句)
在这里插入图片描述

案例:

* 需求: 查询user表,数据存储到List集合
* 实现步骤:
*   1:创建对象 SqlSessionFactoryBuilder
*     工厂的构建者对象,作用创建SQLSession对象工厂的
*     读取配置文件
*
*   2: SqlSessionFactory工厂创建
*      SqlSession接口实现类对象
*
*   3:  SqlSession接口实现类对象
*     调用方法 select 查询数据表
*
*   4: 输出查询结果集
*
*   5: 释放资源
public void myBatisQuickStart(){
    //1:创建对象 SqlSessionFactoryBuilder
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    //使用sqlSessionFactoryBuilder方法 build(),创建出SqlSessionFactory对象
    //build方法,读取配置文件,返回SqlSessionFactory对象,需要传递流对象,流对象绑定数据库配置文件
    InputStream inputStream =  QuickStart.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml");
    // 2: SqlSessionFactory工厂创建
    SqlSessionFactory sqlSessionFactory =  sqlSessionFactoryBuilder.build(inputStream);
    //工厂对象,获取SqlSession接口实现类对象,工厂对象的方法 openSession
    SqlSession sqlSession =  sqlSessionFactory.openSession();
    //3:  SqlSession接口实现类对象,调用方法 select 查询数据表
    //selectList方法参数不是SQL语句, namespace+"."+id 锁定SQL语句  test.queryList
    List<User> userList = sqlSession.selectList("test.queryList");
    for(User user :userList){
        System.out.println(user);
    }
    sqlSession.close();
}

1.4 Java中的日志组件(扩展)

#log4j日志级别如下:
#A:off     最高等级,用于关闭所有日志记录。
#B:fatal   指出每个严重的错误事件将会导致应用程序的退出。
#C:error   指出虽然发生错误事件,但仍然不影响系统的继续运行。
#D:warn    表明会出现潜在的错误情形。
#E:info    一般和在粗粒度级别上,强调应用程序的运行全程。
#F:debug   一般用于细粒度级别上,对调试应用程序非常有帮助。
#G:all     最低等级,用于打开所有日志记录。

#但log4j只建议使用4个级别,优先级从高到低分别是:
#error>warn>info>debug

log4j.rootLogger =debug,systemOut(日志输出到控制台),logFile(日志输出到文件)

#输出到控制台
log4j.appender.systemOut = org.apache.log4j.ConsoleAppender
log4j.appender.systemOut.layout = org.apache.log4j.PatternLayout
log4j.appender.systemOut.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.systemOut.Target = System.out

#输出到文件
log4j.appender.logFile = org.apache.log4j.FileAppender
log4j.appender.logFile.layout = org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.logFile.File = E:/log/log4j.log
log4j.appender.logFile.Encoding = UTF-8

#将日志输记录到MySQL数据库
#log4j.appender.logDB = org.apache.log4j.jdbc.JDBCAppender
#log4j.appender.logDB.layout = org.apache.log4j.PatternLayout
#log4j.appender.logDB.Driver = com.mysql.jdbc.Driver
#log4j.appender.logDB.URL = jdbc:mysql://localhost:3306/log4j?characterEncoding=utf-8
#log4j.appender.logDB.User = root
#log4j.appender.logDB.Password = root
#log4j.appender.logDB.Sql = INSERT INTO t_log4j(project_name,create_date,level,category,file_name,thread_name,line,all_category,message)values('mybatis','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')

2 MyBatis框架的CRUD

2.1 查询

SqlSession对象方法selectList(见快速入门)
sqlSession对象方法selectOne

<mapper namespace="test">
    <!--
          配置,主键查询的SQL语句 ,标签 select
           test+.+id 锁定唯一SQL语句,具有唯一性
          查询是有结果集
            标签中属性 resultType:配置结果集的类型
          SQL语句有参数的
            标签中属性 parameterType: SQL语句的参数类型
            SQL语句中的取参数语法 #{基本类型 任意命名}
    -->
    <select id="queryUserById" resultType="com.itheima.pojo.User" parameterType="Integer">
      <!--
        SQL语句
          MyBatis配置SQL语句,参数不能写问号
          取参数  #{参数名}
          参数名,如果只有一个参数,基本类型及其包装类和String,任意
      -->
        select * from user where id = #{id}
    </select>


   	<!--
	      select 标签,配置的是查询语句
	      id 属性,唯一性,在当前文件中唯一  ,属性值 queryList
	      框架执行SQL语句: namespace+"."+queryList  确定SQL语句
	
	      resultType: 查询的结果集,是pojo对象
	      标签体: 是SQL语句
  	-->
	<select id="queryList" resultType="com.itheima.pojo.User">
      select * from user
   	</select>
</mapper>
 @Test
 /**
  * 框架:查询数据表user,根据主键查询
  */
 public void testQueryUserById() throws IOException {
     /*//1:SqlSessionFactoryBuilder
     SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
     //MyBatis框架提供类, Resources静态方法 getResourceAsStream() 底层封装的就是类加载器,中的流
     InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");//自动从src源码目录下读取文件
     SqlSessionFactory sqlSessionFactory =  sqlSessionFactoryBuilder.build(inputStream);
     //2:创建 SqlSession接口实现类对象*/

     SqlSession sqlSession = sqlSessionFactory.openSession();
     //3:方法,执行SQL语句
     //selectOne(namespace+"."+id 锁定唯一SQL,  SQL语句的实际参数)方法,查询结果一个对象
     User user =  sqlSession.selectOne("test.queryUserById",3);
     System.out.println(user);
     sqlSession.close();
 }

2.2 关于模糊查询

select * from user where username like #{value}
or
select * from user where username like ${value}

#{} ${} 获取参数的区别
Tomcat编译过程的差异:

select * from user where username like #{value}
参数编译为 ?
select * from user where username like ?    
传递的实际参数 "'%王%'" ,替换到?占位符
原理:框架底层使用的JDBC中的接口 PreparedStatement,使用PreparedStatement为占位符?赋值,而不是字符串的拼接

select * from user where username like ${value}
直接拼接了字符串!!
select * from user where username like '%王%'

推荐使用#{},即占位符的方式,效率更高
${}适合于特殊场景, SQL语句中的参数是 列名或者表名的时候
select * from user order by 列名

2.3 插入

配置新增数据,标签insert
新增数据,SQL语句中,一定会有很多参数
参数封装在pojo对象,配置的时候为标签属性parameterType
SQL语句中参数的必须传递pojo对象中的属性名
增删改,结果是行数,int类型,不要配置resultType

新增操作:insert标签中,子标签 <selectKey> 获取上一次新增主键值
属性:
order="after或者before" 获取主键,是在SQL语句之前,还是之后执行
resultType 获取主键的结果数据类型
keyProperty 属性,查询后的值存放:pojo对象的属性中
<insert id="saveUser" parameterType="com.itheima.pojo.User">
  <!--
     传递的参数是对象 pojo
     #{pojo对象的属性名!!}
  -->
   insert into user values (null,#{username},#{sex},#{birthday},#{address})

   <selectKey order="AFTER" resultType="Integer" keyProperty="id">
       SELECT LAST_INSERT_ID ()
   </selectKey>
</insert>
 /**
  * 实现数据的新增。SQL语句参数,封装到pojo对象中
  * SQLSession接口方法 insert
  * 注意: 新增,修改,删除,动了数据表的数据 (事务)
  * 并没有提交事务    sqlSession.commit();//提交事务
  */
 public void testSaveUser(){
     SqlSession sqlSession = sqlSessionFactory.openSession();
     User user = new User();
     user.setUsername("孙尚香");
     user.setSex("女");
     user.setAddress("东吴");
     user.setBirthday( new Date());
     int row = sqlSession.insert("test.saveUser",user);

     sqlSession.commit();//提交事务

     System.out.println(row);
     System.out.println(user);
     sqlSession.close();
 }

2.4 更新

<!--
      配置更新数据,标签update
-->
<update id="updateUserById" parameterType="com.itheima.pojo.User">
    update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}
</update>
@Test
/**
 * 实现更新数据
 */
public void testUpdateUserById(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    User user = new User();
    user.setId(8);
    user.setUsername("孙小妹");
    user.setSex("男");
    user.setBirthday(new Date(0));
    user.setAddress("益州");

    int row = sqlSession.update("test.updateUserById",user);
    sqlSession.commit();
    sqlSession.close();
    System.out.println(row);
}

2.5 删除

 <!--
   配置删除数据,标签delete
 -->
 <delete id="deleteUserById" parameterType="Integer">
     delete from user where id = #{id}
 </delete>
/**
* 实现数据删除
*/
public void testDeleteUserById(){
  SqlSession sqlSession = sqlSessionFactory.openSession();
  int row = sqlSession.delete("test.deleteUserById", 8);
  sqlSession.commit();
  sqlSession.close();
  System.out.println(row);
}

2.6 关于事务(原始dao层开发)

在三层架构中,我们的事务处理都是放在service层处理的。在Mybatis框架中,我们使用SqlSession 对象来执行sql语句,执行事务。但是事务是应该放到service层处理的。

在这里插入图片描述
处理方法:
业务层建立SqlSession 对象,将SqlSession参数传递到dao层,处理sql语句。业务层SqlSession提交事务
例子:
service层:

 /**
  * 本类看成业务层
  * 调用dao层,获取查询的结果
  * 获取SqlSession对象,传递到业务层
  */
 public void testDao(){
     SqlSession sqlSession = sqlSessionFactory.openSession();
     UserDao userDao = new UserDaoImpl(sqlSession);
     List<User> userList = userDao.queryUser();
     for (User user : userList){
         System.out.println(user);
     }
     sqlSession.close();
 }

dao层:

public class UserDaoImpl implements UserDao {
    private SqlSession sqlSession;

    public UserDaoImpl(SqlSession sqlSession){
        this.sqlSession = sqlSession;
    }

    @Override
    /**
     *  重写接口的方法,查询数据库
     *  需要的对象 SqlSession
     *  业务层传递的,不应该自己获取(事务安全性)
     */
    public List<User> queryUser() {
        List<User> userList = sqlSession.selectList("test.queryList");
        return userList;
    }
}

2.7 关于代码优化

在MyBatis中,我们操作数据库的过程分为三步

 *  1:SqlSessionFactoryBuilder
 *    读取配置文件,创建出现 SqlSessionFactory
 *    方法build(输入流)  只需要绑定主文件配置文件
 *
 *  2: SqlSessionFactory 工厂对象
 *    创建 SqlSession接口实现类对象
 *
 *  3: SqlSession接口实现类对象
 *    方法,执行SQL语句

每次执行CRUD,都需要绑定配置文件,创建SqlSession对象,这样代码的重复度很高。
解决办法:将绑定配置文件作为每次执行前的固定方法提出来
将SqlSession对象作为类的成员属性

private SqlSessionFactory sqlSessionFactory;

/**
* junit注解@before,在每次执行@Test修饰方法之前都会执行before方法
*/
@Before
public void before() throws IOException {
   SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
   InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
   sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
}

3 动态代理开发

3.1 原始dao层开发方式

  • 实现步骤
    • 定义dao层接口
    • 定义dao层接口实现类

传统dao开发方式中的实现类其实起了一个连接、承上启下的作用,连接了接口和xml映射文件,效果就是调用接口方法时能够找到xml映射文件。
在这里插入图片描述

3.2 动态代理开发快速入门

定义一个Mapper接口,这个接口其实和我们UserDao接口是一样的,从Mybatis框架中拿到一个代理对象(代理的是这个Mapper接口),通过代理对象调用接口当中的方法完成业务。

Mapper动态代理开发遵从的规范

  • sql映射文件的namespace必须和mapper接口的全限定类名保持一致
  • mapper接口的接口方法名必须和xml中的sql语句id保持一致
  • mapper接口的接口方法形参类型必须和sql语句的输入参数类型保持一致
  • mapper接口的接口方法返回类型必须和sql语句的resultType保持一致
 * MyBatis动态代理开发 (以后都使用方式) 简化开发
 * 限制:
 *   dao层包名,修改为mapper
 *   定义接口 UserMapper,查询所有数据的方法(抽象)
 *   MyBatis框架,自动为我们生成接口的实现类对象
 *
 *   UserMapper.xml配置文件,配置的是user表的SQL语句
 *   配置文件,必须和接口在同一目录下
 *
 *   配置文件中的属性 namespace,的属性值必须和接口的全类名一致
 *
 *   接口中的方法名,必须和SQL语句标签的id值相同
 *   参数和返回值都必须相同
 *
 *   XXXMapper.xml配置文件的路径不要写错

举例子:
UserMapper.java

/**
 * 操作数据表user的接口
 */
public interface UserMapper {
    /**
     * 用户名模糊查询
     * 方法的参数是UserVO对象
     * UserVO对象中包装User对象
     * User对象中,包含用户名
     */
    List<User> queryUserByName(UserVO userVO);


    /**
     * 新增数据
     * 使用注解的方式就不用需要编写xml配置文件了
     */
    //@Insert(" insert into user values (null,#{username},#{sex},#{birthday},#{address})")
    int saveUser(User user);

    /**
     * 根据主键查询一个用户
     */
    User queryUserById(Integer id);

    /**
     * 查询所有数据
     */
    List<User> queryUser();

}



public class UserVO {
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "UserVO{" +
                "user=" + user +
                '}';
    }
}

@Data
public class User {
    private int id;
    private String username;
    private String sex;
    private Date birthday;
    private String address;
}

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="com.itheima.mapper.UserMapper">

    <!--用户名模糊查询-->
    <select id="queryUserByName" resultType="user" parameterType="com.itheima.pojo.UserVO">
        select * from user where username like #{user.username}
    </select>

    <!--配置新增-->
    <insert id="saveUser" parameterType="user">
          insert into user values (null,#{username},#{sex},#{birthday},#{address})
    </insert>

    <!--配置主键查询-->
    <select id="queryUserById" parameterType="Integer" resultType="user">
        select * from user where id = #{id}
    </select>

   <!--配置查询所有的user表数据-->
    <select id="queryUser" resultType="user">
        select * from user
    </select>

</mapper>

测试类统一见下面3.3的测试

3.3 MyBatis手动映射

当数据表中的列名pojo中类的属性名不同时,将会出现封装数据失败的现象,MyBatis无法将数据表中的数据准确的封装到pojo对象中,因此必须使用手动映射的方式来实现。
举个例子:
数据库表中字段:

CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '下单用户id',
  `number` varchar(32) NOT NULL COMMENT '订单号',
  `createtime` datetime NOT NULL COMMENT '创建订单时间',
  `note` varchar(100) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`)
)

pojo类orders.java

@Data
public class Orders{
    private Integer id;

    private Integer userId;

    private String number;

    private Date createtime;

    private String note;
}

注意userid是不对应的
定义OrdersMapper.java接口

public interface OrdersMapper {
    /**
     * 查询定的的全部数据
     */
    List<Orders> queryOrders();
}

如何编写OrdersMapper.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.itheima.mapper.OrdersMapper">

<!--
        配置查询所有定的的SQL
       查询需要使用自己配置的映射!!
       select 标签属性resultMap,属性值,请你写手动映射标签resultMap的id值
-->
    <select id="queryOrders" resultType="orders" resultMap="ordersResultMap">
        select * from orders
    </select>

    <!--
            手动映射,手动配置pojo对象的属性名和,数据表的列名resultMap
            属性: id=""唯一性
            type 结果类型,pojo对象

    -->
    <resultMap id="ordersResultMap" type="orders">
        <!--配置的就是 数据表的列,和pojo对象成员变量的对应关系-->

        <!--id配置的是主键
            columns列名
            property pojo对象属性名
        -->
        <id column="id" property="id"></id>

        <!--配置其他列-->
        <result column="user_Id" property="userId"></result>
        <result column="number" property="number"></result>
        <result column="createtime" property="createtime"></result>
        <result column="note" property="note"></result>
    </resultMap>
</mapper>

测试类:
MyBaitsProxy.java

public class MyBaitsProxy {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void before() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        sqlSessionFactory =  sqlSessionFactoryBuilder.build(inputStream);
    }

    @Test
    /**
     * 动态代理,代理的接口是OrdersMapper接口
     * 帮我们自动生成了OrdersMapper接口的实现类
     */
    public void testQueryOrders(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
        List<Orders> ordersList = ordersMapper.queryOrders();
        for (int i = 0; i < ordersList.size(); i++) {
            Orders orders =  ordersList.get(i);
            System.out.println(orders);
        }
    }


    @Test
    /**
     * 动态代理方式,代理mapper包下的接口
     * 用户名模糊查询
     */
    public void testQueryUserByName(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
        User user = new User();
        user.setUsername("%王%");

        UserVO userVO = new UserVO();
        userVO.setUser(user);

        List<User> userList = userMapper.queryUserByName(userVO);
        for (int i = 0; i < userList.size(); i++) {
            User user1 =  userList.get(i);
            System.out.println(user1);
        }
        sqlSession.close();
    }

    /**
     * 动态代理方式,代理mapper包下的接口
     * 数据新增
     */
    @Test
    public void testSaveUser(){
        User user = new User();
        user.setUsername("赵云");
        user.setSex("男");
        user.setAddress("河北正定");
        user.setBirthday(new Date());

        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
        int row = userMapper.saveUser(user);
        sqlSession.commit();
        sqlSession.close();
    }

    /**
     * 动态代理方式,代理mapper包下的接口
     * 主键查询
     */
    @Test
    public void testQueryUserById(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper =  sqlSession.getMapper(UserMapper.class);
        User user = userMapper.queryUserById(6);
        System.out.println(user);
        sqlSession.close();
    }

    @Test
    /**
     * 动态代理方式,代理的是mapper包下的接口
     */
    public void testQueryUser(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //SqlSession接口方法 getMapper()
        /*
             参数是被代理的接口的class文件对象
             返回值就是被代理接口的实现类对象

             UserMapper接口的实现类
         */
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.queryUser();
        for(User user : userList){
            System.out.println(user);
        }
        sqlSession.close();
    }
}

3.4 关于配置文件SqlMapConfig.xml

主要两个点:重命名和sql语句的xml文件配置路径
A:全局typeAliases配置
定义别名,两种方式:

  1. 直接定义

    typeAliase 标签定义一个类的别名, Users类定义别名user
    <typeAlias type="com.itheima.pojo.Users" alias="user"/>
    
  2. package 标签批量定义,包扫描,写包名

        自动扫描包,包下的类,进行别名定义
        定义的别名,就是类名
        <typeAliases>
            <package name="com.itheima.pojo"/>
        </typeAliases>
    

B:全局配置文件mappers
mappers注册sql映射文件的

  • resource属性加载sql映射文件,万能型选手(crud、原始dao、mapper动态代理)
  • 针对Mapper动态代理进行一个增强(增强两种用法)
  • mapper class 单个注册
  • package 批量扫描注册
  • 以上两种方式有规范要求

说明:
mapper配置的xml文件的路径(SQL语句配置文件),一个数据表对应一个xml

配置路径,两种方式:

  1. mapper标签的属性 resource=“xml路径”
    使用resource标签,一般xml不多的情况

    <mapper resource="StudentMapper.xml"/>
    
  2. package标签的属性 name=“包名”
    使用package批量扫描路径,一般有很多xml的情况

    <package name="com.itheima.mapper"></package>
    

总体所有配置举个例子:

<?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文件
        实用价值不大
    -->
    <properties resource="db.properties"></properties>

    <!--别名配置typeAliases-->
    <typeAliases>
        <!--配置一个别名,数据类型是、pojo对象,简化为user-->
        <!--<typeAlias type="com.itheima.pojo.User" alias="user"/>-->

        <!--
                定义别名,是用package包扫描,扫描到pojo包
                类名就是重命名
        -->
        <package name="com.itheima.pojo"/>
    </typeAliases>


    <environments default="development">
        <environment id="development">

            <transactionManager type="JDBC" />

            <dataSource type="POOLED">
                <!--配置的是,数据库连接四大信息-->
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>



    </environments>

    <!--
      配置的是映射关系  ORM Java对象和数据表
    -->
    <mappers >
        <!--
             自动扫描配置
             mapper配置的xml文件的路径(SQL语句配置文件)
             一个数据表对应一个xml

             mapper标签的属性 resource="xml路径"
             package标签的属性 name="包名"

             <package name="com.itheima.mapper"></package>
             框架自动扫描配置的包下的xml文件
        -->
        <package name="com.itheima.mapper"></package>

        <!--<mapper resource="StudentMapper.xml"/>-->
    </mappers>
</configuration>    

4 动态代理原理(先空着)

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值