MyBatis 学习(一)

MyBatis 学习(一)

1、什么是MyBatis? MyBatis有什么作用?

  • MyBatis 是一款优秀的持久层框架
  • 它支持自定义 SQL、存储过程以及高级映射。
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
  • MyBatis 可以通过简单的 XML注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

2、如何获得MyBatis?

3、持久化:

  • (数据持久化)是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据库(jdbc),io文件持久化
  • 生活:冷藏食品。。
  • 为什么需要持久化:有些对象不能让他丢掉。需要持久化操作
4、持久层:
  • Dao层、Service层、Controller层
  • 完成持久化工作的代码块
  • 层的界限十分明显。

二、第一个MyBatis程序

思路:搭建环境-》导入MyBatis依赖--》编码--》测试!

0、创建Maven项目导入mybatis相关依赖

<!--导入依赖-->
    <dependencies>
        <dependency>
            <!--mysql驱动-->
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!--mybatis-->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!--junit测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

1、在resource资源目录创建mybatis-config.xml :注册mysql驱动连接数据库

<!--configuration核心配置文件-->
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--注册mysql驱动-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=ture&amp;useUnicode=ture&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

</configuration>

2、创建mybatisUtils工具类:通过构建 SqlSessionFactory从而获取SQLSession

//2、构建 SqlSessionFactory从而获取SQLSession(工厂类-》商品)
public class MyBatisUtils {

    private static  SqlSessionFactory sqlSessionFactory;

    // SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。
    // 而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例
    static {
        try {
            //获取SqlSqlSessionFactory 对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /*有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
     SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
     则可以通过 SqlSession 实例来直接执行已映射的 SQL 语句*/
    public static SqlSession getSqlSession() {

      return sqlSessionFactory.openSession();
    }

}

3、User实体类:与数据表的字段一致

//3、与数据库对应的实体类
public class User {
    private int id;
    private String username;
    private int password;
    ........
}  

4、业务行为接口 UserDao

public interface UserDao {
    List<User> getUserList();
}

5、通过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">
<!--5、通过xml使用SqlSession-->
<!--namespace绑定一个对应的UseDao/Mapper接口-->
<mapper namespace="com.study.dao.UserDao">
    <!--select查询语句:id:接口中的方法名;resultType:返回结果类型(实体类的全限定名)-->
    <select id="getUserList" resultType="com.study.pojo.User">
        select  * from mybatis.user
    </select>
</mapper>

===================================================================
//原来的JDBC写法对比xml
public class UserDaoImpl  implements UserDao{

    @Override
    public List<User> getUserList() {
       //连接数据库驱动
        //sql语句
        String str ="select  * from mybatis.user" ;
        // 返回 Resultset 结果集
       return  .....;
    }
}

6、测试类:

public class UserDaoTest {
    @Test
    public  void test(){
        //第一步:获取SqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
         //第二步:执行SQL(如何拿到Sql,获取接口的class对象)
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        //获得UserList集合
        List<User> userList = userDao.getUserList();
        //遍历输出
        for (User user : userList) {
            System.out.println(user);
        }

        //关闭SQLSession
        sqlSession.close();

    }
}

7、在运行mybatis是出现的错误及解决方法

mybatis报错2
  • 解决:原因是在构建SqlSession失败,在config.xml中找到没有将配置好的Mapper.xml添加到核心配置文件中去

    即在configuration加入下面语句:

    <!--每一个Mapper.xml都需要在mybatis核心配置文件中注册!-->
    <mappers>
         <mapper resource="com/study/dao/UserMapper.xml"/>
    </mappers>
    

问题二:

image-20210310233558372

解决:这是运行时没有发现创建在java下的xml文件,则需要在Maven配置(最好在父子工程下的poml文件都配置)

<!--maven由于他的约定大于配置,我们之后再写配置,无法被导出或者生效的问题-->
    <!--在build中配置resource,来防止我们资源导出失败的问题-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
       </resources>

问题三:

image-20210310234107527

解决:这个问题解决了好长时间是由于粗心编码错误问题(公共变量的定义),因为SQLSessionFactory在外面已经定义,里面无需再定义,否侧拿到到的一直是null值

image-20210310234402954

问题四:【true】

image-20210310234708092

成功运行:

image-20210310235441070

问题五

IDEA打包是遇到的错误(package:主要是为了看清楚Taget目录下有多少文件可以编译运行)

image-20210310234847635

image-20210310235154217

  • 在使用打包是应该在pom中添加maven在

    //build标签中
    <!--package打包插件-->
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.4.2</version>
                    <configuration>
                        <skipTests>true</skipTests>
                    </configuration>
                </plugin>
            </plugins>
    
    <properties>
            <!--Maven 打包时有标题中警告,需要在pom.xml文件中添加-->
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
    

三、基本理论

1、SqlSessionFactoryBuilder
  • 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。

    因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

  • 可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

2、SqlSessionFactory
  • sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。

  • 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

3、SqlSession
  • SqlSession sqlSession = sqlSessionFactory.openSession();
    
  • 每个线程都应该有它自己的 SqlSession 实例。

  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域

  • 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。

四、CRUD

1、namespace
  • 命名空间的作用有两个,一个是利用更长的全限定名来将不同的语句隔离开来,同时也实现了你上面见到的接口绑定

  • 长远来看,只要将命名空间置于合适的 Java 包命名空间之中,你的代码会变得更加整洁,也有利于你更方便地使用 MyBatis。

  • 命名解析:

    • 全限定名(比如 “com.mypackage.MyMapper.selectAllThings)将被直接用于查找及使用。
  • 注:namespace的命名就是dao/mapper接口的全限定名

2、Select 查询
  • id:就是对应的namespace(接口)中的方法名;
  • resultType:Sql语句执行的返回值类型;
  • parameterType:传参的类型;

UserMapper接口:所要实现的功能

  • /*4、功能接口*/
    public interface UserDaoMapper {
        //查询所有用户
        List<User> getUserList();
        //通过id查询用户
        User getUserById(int id);
        //添加用户
        boolean insertUser(User user);
        //修改用户
        boolean updataUser(User user);
        //删除用户
        boolean deleteUser(int id);
    }
    

UserMapper.xml:查询语句(实现接口)

  •   <!--select查询语句:id:接口中的方法名;resultType:返回结果类型(实体类的全限定名)-->
        <select id="getUserList" resultType="com.study.pojo.User">
            select  * from mybatis.user
        </select>
        <!--通过id查询用户-->
        <select id="getUserById"  parameterType="int" resultType="com.study.pojo.User" >
            select * from mybatis.user where id = #{id}
        </select>
    

UserTest测试:

  •  /*通过id查询用户*/
        @Test
        public void getUserById(){
            //1.获取sqlsession
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
            //获得Mapper对象(获得接口)
            UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class);
            //执行sql并返回结果
            User user = mapper.getUserById(1);
            System.out.println(user);
    
            //关闭
            sqlSession.close();
        }
    
3、Insert 插入

UserMapper.xml:查询语句(实现接口)

  •  <!--添加用户(User对象的属性可以直接取出来)-->
        <insert id="insertUser" parameterType="com.study.pojo.User" >
            insert  into mybatis.user (id,username,password) values (#{id},#{username},#{password})
        </insert>
    

UserTest测试:

  •  /*增删改都需要提交事务*/
        /*添加用户*/
        @Test
        public void insertUser(){
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class);
            boolean user = mapper.insertUser(new User(6,"lijing2",2444));
            System.out.println(user);
    
            sqlSession.commit();
            sqlSession.close();
        }
    
4、Delete 删除

UserMapper.xml:查询语句(实现接口)

  • <!--删除用户-->
        <delete id="deleteUser" parameterType="int">
            delete from  mybatis.user where id=#{id}
        </delete>
    

UserTest测试:

  •   /*删除用户*/
        @Test
        public void deleteUser(){
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
            UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class);
    
            boolean user = mapper.deleteUser(6);
            System.out.println(user);
    
            sqlSession.commit();
            sqlSession.close();
    
        }
    
5、Update 修改

UserMapper.xml:查询语句(实现接口)

  •  <!--通过id修改用户-->
        <update id="updataUser" parameterType="com.study.pojo.User" >
            update mybatis.user set username = #{username},password= #{password} where id =#{id}
        </update>
    

UserTest测试:

  •  /*更新用户*/
        @Test
        public  void updataUser(){
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class);
            boolean user = mapper.updataUser(new User(5, "哈哈", 00000000));
            System.out.println(user);
    
            sqlSession.commit();
            sqlSession.close();
    
        }
    

注: 增删改都需要提交事务commit,数据库才会更新。

6、万能的Map

假设,我们的实体类有很多属性,或者数据库中的表,字段或者参数过多,就应当考虑使用Map!

  • 使用map作为参数传递是不需要知道数据有什么子段。

  • 在Sql语句编写是字段可以自定义不必和数据的字段一致。

  • //通过map查询用户
        boolean addUserMap(Map<String,Object> map);
    
    <!--使用map添加用户(不用静User的所有属性写出来也不用new User)-->
        <insert id="addUserMap" parameterType="map" >
            insert into mybatis.user (id,username,password) values (#{userid},#{name},#{pwd})
        </insert>
    
     /*通过map添加用户*/
        @Test
        public  void addUserMap(){
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
            UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class);
    
            /*创建Map对象*/
            Map<String, Object> map = new HashMap();
            map.put("userid",6);
            map.put("name","opop");
            map.put("pwd",88888);
    
            boolean userMap = mapper.addUserMap(map);
            System.out.println(userMap);
    
            sqlSession.commit();
            sqlSession.close();
        }
    
  • Map传递参数,直接在sql中取出key即可 【parameterType="map"】

  • 而对象传递参数,直接在sql中取对象的属性即可【parameterType="类的全限定名"】

  • 只有一个基本类型参数的情况下,可以直接在sql取到!

  • 多个参数用Map,或者注解!

7、Like模糊查询
  • 第一种:java代码执行的时候,传递通配符%%

    List<User> userLike = mapper.getUserLike("%哈%");
    
    <select id="getUserLike" resultType="com.study.pojo.User">
    select  * from mybatis.user where  username LIKE #{value}
    </select>
    
    
  • 第二种:在SQL拼接中使用通配符

    <select id="getUserLike" resultType="com.study.pojo.User">
            select  * from mybatis.user where  username LIKE  "%"#{value}"%"
     </select>
    
    List<User> userLike = mapper.getUserLike("哈");
    

五、配置解析

  • MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息

环境配置:

  • MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。
  • 不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
  • 事务管理器(transactionManager)
    • 在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
    • JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
    • MANAGED – 这个配置几乎没做什么。默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。
  • 连接池:POOLED
  • 如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
1、属性设置之配置优化
  • 属性(properties)

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置

  • 我们可以通过properties属性来实现引用配置问文件。

  • 1、db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=root
  • 2、在配置文件中引入

  • 注:配置文件中引入要注意其顺序

  • image-20210313231142467
    <!--1、configuration核心配置文件-->
    <configuration>
        <!--引入外部配置文件-->
         <properties resource="db.properties"/>
        <!--默认环境-->
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <!--连接的数据源-->
                <dataSource type="POOLED">
                    <!--注册mysql驱动-->
                    <property name="driver" value="${driver}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${username}"/>
                    <property name="password" value="${password}"/>
                </dataSource>
            </environment>
        </environments>
        <!--每一个Mapper.xml都需要在Mybatis核心配置文件注册!-->
        <mappers>
            <mapper resource="com/study/dao/UserMapper.xml"/>
        </mappers>
    </configuration>
    
    
    或:这样的写法
    <properties resource="db.properties">
            <property name="username" value="root"/>
            <property name="password" value="root"/>
    </properties>
    
  • 可以直接引入外部文件

  • 可以在其中增加一些属性配置】

  • 如果两个文件有同一个字段,优先使用外部引用的文件!

2、类型别名(typeAliases)
  • 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写

  • 我们在xml编写sql时需要指定resultType就是全限定类名这是就可以简化

  • 第一种方式:

     <!--简化全限定类名,起别名-->
        <typeAliases>
            <typeAlias type="com.study.pojo.User" alias="User"/>
        </typeAliases>
    
    <select id="getUserList" resultType="User">
            select  * from mybatis.user
     </select>
    
    
  • 第二种:也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

    <!--扫描包名,会默认使用 Bean 的首字母小写的非限定类名来作为它的别名-->
        <typeAliases>
            <package name="com.study.pojo"/>
        </typeAliases>
    
    <select id="getUserList" resultType="user">
            select  * from mybatis.user
     </select>
    

    每一个在包com.study.pojo 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。

    • 在实体类比较少的时候,使用第一种方式
    • 如果实体类非常多的情况下,建议使用第二种。
    • 第一种可以diy别名,第二种需要diy的则需加在类上加注解@@Alias()
@Alias("UserPoJo")
public class User {
    private int id;
    private String username;
    private int password;
......
}
<!--扫描包名,会默认使用 Bean 的首字母小写的非限定类名来作为它的别名-->
    <typeAliases>
        <package name="com.study.pojo"/>
    </typeAliases>

<select id="getUserList" resultType="UserPoJo">
        select  * from mybatis.user
    </select>
3设置(settings)
  • 这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为
设置名 描述 有效值 默认值
cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 true | false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 true | false false
useGeneratedKeys 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。 true | false False
mapUnderscoreToCamelCase 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 true | false False
image-20210316223504656
4、其他配置

typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)

  • maven:mybatis-generator_core
  • mybatis-plus
  • 通用mapper
5、映射器(Mapper)
  • 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。
  • MapperRegistry:注册绑定我们的Mapper文件

方式一:

  • <!--每一个Mapper.xml都需要在mybatis核心配置文件中注册!-->
    <mappers>
         <mapper resource="com/study/dao/UserMapper.xml"/>
    </mappers>
    

方式二:使用class文件绑定注册

  • <!--每一个Mapper.xml都需要在mybatis核心配置文件中注册!-->
    <mappers>
         <mapper class="com.study.dao.UserMapper"/>
    </mappers>
    
  • 注意点:

    • 1、接口和他的Mapper配置文件必须同名!
    • 2、接口和他的Mapper配置文件必须在同一个包下!

方式三:使用扫描包进行注入绑定

  • <mappers>
            <package name="com.study.dao"/>
     </mappers>
    

注意点:

  • 1、接口和他的Mapper配置文件必须同名!
  • 2、接口和他的Mapper配置文件必须在同一个包下!
6、作用域(Scope)和生命周期

SqlSessionFactoryBuilder

  • 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。

    因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

SqlSessionFactory

  • 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次。因此 SqlSessionFactory 的最佳作用域是应用作用域

SqlSession

  • SqlSession sqlSession = sqlSessionFactory.openSession();
    
  • 每个线程都应该有它自己的 SqlSession 实例。

  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域

image-20210316231958303image-20210316233952132

image-20210316234032214
原文地址:https://www.cnblogs.com/yyb6/p/14590075.html