MyBatis两种方式入门和区别+基于xml配置的CRUD+包装类ongl用法+设计模式应用

MyBatis基础入门

1.MyBatis 框架概述

解决数据持久化问题的框架

1.mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,
而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
2.mybatis 通过 xml 或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中
sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并
返回。
3.采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了 jdbc api 底层访问细节,使我
们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。

4.四个核心组件

  • 构造器SqlSessionFactoryBuilder
  • 工厂接口SqlSessionFactory
  • 会话接口SqlSession
  • 映射器SQL Mapper

2.JDBC弱点分析

1、数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
2、Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java
代码。
3、使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能
多也可能少,修改 sql 还要修改代码,系统不易维护。
4、对结果集解析存在硬编码(查询列名),sql 变化导致解析代码变化,系统不易维护,如果能将数据库记
录封装成 pojo 对象解析比较方便。

3.ORM思想和JDBC封装

在这里插入图片描述

在这里插入图片描述

4.Mybatis快速入门

4.1 添加sql
# create database mybatis;
use  mybatis;
CREATE TABLE `user` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` datetime default NULL COMMENT '生日',
  `sex` char(1) default NULL COMMENT '性别',
  `address` varchar(256) default NULL COMMENT '地址',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (41,'老王','2018-02-27 17:47:08','男','北京'),(42,'小二王','2018-03-02 15:09:37','女','北京金燕龙'),(43,'小二王','2018-03-04 11:34:34','女','北京金燕龙'),(45,'传智播客','2018-03-04 12:04:06','男','北京金燕龙'),(46,'老王','2018-03-07 17:37:26','男','北京'),(48,'小马宝莉','2018-03-08 11:44:00','女','北京修正');

CREATE TABLE `account` (
  `ID` int(11) NOT NULL COMMENT '编号',
  `UID` int(11) default NULL COMMENT '用户编号',
  `MONEY` double default NULL COMMENT '金额',
  PRIMARY KEY  (`ID`),
  KEY `FK_Reference_8` (`UID`),
  CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `account`(`ID`,`UID`,`MONEY`) values (1,46,1000),(2,45,1000),(3,46,2000);

CREATE TABLE `role` (
  `ID` int(11) NOT NULL COMMENT '编号',
  `ROLE_NAME` varchar(30) default NULL COMMENT '角色名称',
  `ROLE_DESC` varchar(60) default NULL COMMENT '角色描述',
  PRIMARY KEY  (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `role`(`ID`,`ROLE_NAME`,`ROLE_DESC`) values (1,'院长','管理整个学院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校');

CREATE TABLE `user_role` (
  `UID` int(11) NOT NULL COMMENT '用户编号',
  `RID` int(11) NOT NULL COMMENT '角色编号',
  PRIMARY KEY  (`UID`,`RID`),
  KEY `FK_Reference_10` (`RID`),
  CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`ID`),
  CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `user_role`(`UID`,`RID`) values (41,1),(45,1),(41,2);
4.2创建 maven 工程和添加 Mybatis3.4.5 的坐标
<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
        <scope>test</scope>
    </dependency>
</dependencies>
4.3创建pojo/User.java

在这里插入图片描述

package cn.lj.pojo;

import java.io.Serializable;
import java.util.Date;

/**
 * @author lj
 * @Description: 用户
 * @date 2020-11-24 15:33
 * @QQ 851477108
 */


public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    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 Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
4.4创建dao/UserDao.java
package cn.lj.dao;

import cn.lj.pojo.User;

import java.util.List;

/**
 * @author lj
 * @Description: 用户持久层
 * @date 2020-11-24 15:35
 * @QQ 851477108
 */


public interface UserDao {

    /**
     * 查询所有操作
     * @return
     */
    List<User> findAll();

    /**
     * 保存
     * @param user
     */
    void saveUser(User user);

    /**
     * 根据Id删除用户
     * @param userId
     */
    void deleteUser(Integer userId);

    /**
     * 更新用户
     * @param user
     */
    void updateUser(User user);


    /**
     * 根据id查询用户信息
     * @param userId
     * @return User
     */
    User findById(Integer userId);

    /**
     * 根据名称模糊查询用户信息
     * @param username
     * @return List<User>
     */
    List<User> findByName(String username);

    /**
     * 查询总用户数
     * @return
     */
    int findTotal();

    /**
     * 根据queryVo中的条件查询用户
     * @
     */
    List<User> findUserByVo();
}
4.5在resource下创建mybaits配置文件SqlMpperConfig.xml
-properties(属性)
    --property
-settings(全局配置参数)
    --setting
-typeAliases(类型别名)
    --typeAliase
    --package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
    --environment(环境子属性对象)
        ---transactionManager(事务管理)
        ---dataSource(数据源)
-mappers(映射器)
    --mapper
    --package
<!--config约束-->
<?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">
<!-- mybatis的主配置文件 -->
<configuration>
    <!-- 配置环境 -->
    <environments default="mysql">
        <!-- 配置mysql的环境-->
        <environment id="mysql">
            <!-- 配置事务的类型-->
            <transactionManager type="JDBC"/>
            <!-- 配置数据源(连接池) -->
            <dataSource type="POOLED">
                <!-- 配置连接数据库的4个基本信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->

</configuration>
4.6映射配置文件cn/lj/dao/UserDao.xml,映射配置文件指的是每个dao独立的配置文件
要求:
创建位置:必须和持久层接口在相同的包中。 
名称:必须以持久层接口名称命名文件名,扩展名是.xml
坑:创建resource底下的目录是不能一次创建子目录,要一次只创建一个,不然会出现目录是cn.lj名称
<?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属性必须是dao接口的全限定类名-->
<mapper namespace="cn.lj.dao.UserDao">
<!--映射配置文件的操作配置select,id属性必须dao接口的方法名,resultType是返回结果集类型-实体类的全限定类名-->
    <select id="findAll" resultType="cn.lj.pojo.User">
        select * from user
    </select>
   
        <!--parameterType是参数集类型-实体类的全限定类名-->
    <select id="saveUser" parameterType="cn.lj.pojo.User">
        insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})
    </select>
    
    <select id="updateUser" parameterType="cn.lj.pojo.User">
        update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id}
    </select>

    <select id="deleteUser">
        delete from user where id=#{id}
    </select>
</mapper>
4.7创建日志配置resource/log4j.properties
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

5.开始测试

5.1创建测试文件cn.lj.test.MybatisTest.java

在这里插入图片描述

package cn.lj.test;

import cn.lj.dao.UserDao;
import cn.lj.pojo.User;
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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

/**
 * @author lj
 * @Description:
 * @date 2020-11-24 16:20
 * @QQ 851477108
 */


public class MybatisTest {

    private InputStream in;
    private SqlSession sqlSession;
    private UserDao userDao;

    @Before//用于在测试方法执行之前执行
    public void init() throws IOException {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.创建SqlSessionFactory工厂对象,获得数据源配置信息
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3.工厂对象根据信息创建SqlSession对象
        sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的动态代理对象
        userDao = sqlSession.getMapper(UserDao.class);
    }

    @After    //用于在测试方法执行之后执行
    public void destroy()throws Exception{
        //提交事务,如果不提交,会回滚操作,表数据直接跳一行
        sqlSession.commit();
        //6.释放资源
        sqlSession.close();
        in.close();
    }

    @Test
    public void testFindAll() {
        //5.使用代理对象执行方法
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void testSave(){
        User user = new User();
        user.setUsername("lj");
        user.setAddress("上海");
        user.setSex("男");
        user.setBirthday(new Date());
        userDao.saveUser(user);
        System.out.println("保存操作之后:"+user);
    }

    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(50);
        user.setUsername("lj-update2");
        user.setAddress("上海");
        user.setSex("男");
        user.setBirthday(new Date());
        userDao.updateUser(user);
        System.out.println("保存操作之后:"+user);
    }

    @Test
    public void testDelete(){
        userDao.deleteUser(49);
    }
}
5.2 测试结果

在这里插入图片描述

5.3查询全过程分析

在这里插入图片描述

    /**
     * 根据名称模糊查询用户信息
     * @param username
     * @return List<User>
     */
    List<User> findByName(String username);

    /**
     * 查询总用户数
     * @return
     */
    int findTotal();
   <select id="findById" parameterType="int" resultType="cn.lj.pojo.User">
        select * from user where id=#{uid}
    </select>

    <select id="findByName" parameterType="string" resultType="cn.lj.pojo.User">
        select * from user where username like #{name}
    </select>
    @Test
    public void testFindOne(){
        User user = userDao.findById(48);
        System.out.println(user);
    }

    @Test
    public void testFindByName(){
        List<User> users = userDao.findByName("%王%");
      
        for (User user : users) {
            System.out.println(user);
        }
    }

第二种模糊查询写法,参数一定是value,不常用

    <select id="findByName" parameterType="string" resultType="cn.lj.pojo.User">
         select * from user where username like '%${value}%'
    </select>     
    @Test
    public void testFindByName(){
     List<User> users = userDao.findByName("王");      
        for (User user : users) {
            System.out.println(user);
        }
    }

在这里插入图片描述

5.4查询一行和模糊查询
    /**
     * 根据名称模糊查询用户信息
     * @param username
     * @return List<User>
     */
    List<User> findByName(String username);

    /**
     * 查询总用户数
     * @return
     */
    int findTotal();
   <select id="findById" parameterType="int" resultType="cn.lj.pojo.User">
        select * from user where id=#{uid}
    </select>

    <select id="findByName" parameterType="string" resultType="cn.lj.pojo.User">
        select * from user where username like #{name}
    </select>
    @Test
    public void testFindOne(){
        User user = userDao.findById(48);
        System.out.println(user);
    }

    @Test
    public void testFindByName(){
        List<User> users = userDao.findByName("%王%");
      
        for (User user : users) {
            System.out.println(user);
        }
    }

第二种模糊查询写法,参数一定是value,不常用

    <select id="findByName" parameterType="string" resultType="cn.lj.pojo.User">
         select * from user where username like '%${value}%'
    </select>     
    @Test
    public void testFindByName(){
     List<User> users = userDao.findByName("王");      
        for (User user : users) {
            System.out.println(user);
        }
    }

在这里插入图片描述

5.5使用selectKey标签返回保存时的用户的ID或者其他
@Test
public void testSave(){
    User user = new User();
    user.setUsername("lj-selectKey");
    user.setAddress("上海");
    user.setSex("男");
    user.setBirthday(new Date());
    System.out.println("保存操作之前:"+user);
    userDao.saveUser(user);
    System.out.println("保存操作之后:"+user);
}
<!--parameterType是参数集类型-实体类的全限定类名-->
<insert id="saveUser" parameterType="cn.lj.pojo.User">
    <!-- 配置插入操作后,获取插入数据的id -->
    <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
        select last_insert_id()
    </selectKey>
    insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})
</insert>
5.6ongl在用户的映射配置文件中配置
ognl 表达式:
它是 apache 提供的一种表达式语言,全称是:Object Graphic Navigation Language 对象图导航语言
它是按照一定的语法格式来获取数据的。语法格式就是使用 #{对象.对象}的方式
#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用
getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user.
而直接写 username。
5.6ongl的用法

见6.2

6.转递pojo包装对象

6.1pojo//QeryVo.java
public class QueryVo {

    private User user;

    public User getUser(){
        return user;
    }

    public void setUser(User user){
        this.user = user;
    }
}
6.2持久层接口映射UserMapper.xml
<select id="findUserByVo" parameterType="cn.lj.pojo.QueryVo" resultType="cn.lj.pojo.User">
    select * from user where username like #{user.username}
</select>
6.3测试包装类作为参数
@Test
public void testFindByVo(){
    QueryVo queryVo = new QueryVo();
    User user = new User();
    user.setUsername("%王%");
    queryVo.setUser(user);
    List<User> users = userDao.findUserByVo(queryVo);
    for (User u : users) {
        System.out.println(u);
    }
}

7.MyBatis设计模式

使用了类加载器Resources

创建型模式

  • 建造者模式Builder
  • 工厂模式factory

结构性模式

  • 动态代理模式

在这里插入图片描述

8.MyBatis第二种开发-传统DAO

使用 Mybatis 开发 Dao,有原始 Dao 开发方式和 Mapper 接口代理开发方式。

而现在主流 的开发方式是接口代理开发方式,这种方式总体上更加简便。

8.1持久层 Dao 接口
/**
* 查询所有用户
* @return
*/
List<User> findAll();
8.2独有的DAO实现类
public class UserDaoImpl implements IUserDao {

    private SqlSessionFactory factory;

    public UserDaoImpl(SqlSessionFactory factory){
        this.factory = factory;
    }

    @Override
    public List<User> findAll() {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询列表
        List<User> users = session.selectList("cn.lj.dao.UserDao.findAll");
        //参数就是能获取配置信息的key
        //3.释放资源
        session.close();
        return users;
    }
}
8.3测试
public class MybatisTest {

    private InputStream in;
    private IUserDao userDao;

    @Before//用于在测试方法执行之前执行
    public void init()throws Exception{
        //1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3.使用工厂对象,创建dao对象
        userDao = new UserDaoImpl(factory);
    }

    @After//用于在测试方法执行之后执行
    public void destroy()throws Exception{
        //6.释放资源
        in.close();
    }

    /**
     * 测试查询所有
     */
    @Test
    public void testFindAll(){
        //5.执行查询所有方法
        List<User> users = userDao.findAll();
        for(User user : users){
            System.out.println(user);
        }
    }
}
8.4两种方式的区别

传统DAO:

  • 有dao实现类方法需要factory对象
  • 使用工厂对象,创建dao对象userDao = new UserDaoImpl(factory)

动态代理DAO:

  • userDao = sqlSession.getMapper(IUserDao.class)获取dao的代理对象
  • 工厂对象根据信息创建SqlSession对象sqlSession = factory.openSession()

本质区别是对工厂对象的使用

传统DAO需要将factory对象给实现类

动态代理DAO需要factory对象创建sqlSession对象,然后获取dao的代理对象

两者最终都需要得到JDBC的Connection对象连接数据库实例,底层基于JDBC操作数据库实例

在这里插入图片描述

都需要使用到四个核心组件

  • 构造器SqlSessionFactoryBuilder
  • 工厂接口SqlSessionFactory
  • 会话接口SqlSession
  • 映射器SQL Mapper
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木子津

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值