Mybatis

Mybatis,第1张

Mybatis 1、对原生态jdbc程序(单独使用jdbc开发)问题总结
Public static void main(String[] args) {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;

            try {
                //加载数据库驱动
                Class.forName("com.mysql.jdbc.Driver");

                //通过驱动管理类获取数据库链接
                connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "mysql");
                //定义sql语句 ?表示占位符
            String sql = "select * from user where username = ?";
                //获取预处理statement
                preparedStatement = connection.prepareStatement(sql);
                //设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
                preparedStatement.setString(1, "王五");
                //向数据库发出sql执行查询,查询出结果集
                resultSet =  preparedStatement.executeQuery();
                //遍历查询结果集
                while(resultSet.next()){
                    System.out.println(resultSet.getString("id")+"  "+resultSet.getString("username"));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                //释放资源
                if(resultSet!=null){
                    try {
                        resultSet.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(preparedStatement!=null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(connection!=null){
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

            }

        }

上面代码有如下几个问题:

1. 数据库连接,使用时创建,不使用就关闭,对数据库进行频繁连接开启和关闭,造成数据库资源的浪费
        解决:使用数据库连接池管理数据库连接

2. 将sql 语句硬编码到Java代码中,如果sql语句修改,需要对java代码重新编译,不利于系统维护
        解决:将sql语句设置在xml配置文件中,即使sql变化,也无需重新编译

3. 向preparedStatement中设置参数,对占位符位置和设置参数值,硬编码到Java文件中,不利于系统维护
        解决:将sql语句及占位符,参数全部配置在xml文件中

4. 从resutSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护。
        解决:将查询的结果集,自动映射成java对象

2、Mybatis框架原理(掌握)  1.什么是Mybatis?

1. mybatis是一个持久层的框架,是apache下的顶级项目。
2. mybatis托管到goolecode下,后来托管到github下:mybatis Github地址
3. mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。
4. mybatis可以将向 preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)

 2.Mybatis原理图

 mybatis和hibernate本质区别和应用场景

hibernate:

        是一个标准ORM框架(对象关系映射)。入门门槛较高的,不需要程序写sql,sql语句自动生成了。对sql语句进行优化、修改比较困难的。

应用场景:适用与需求变化不多的中小型项目,比如:后台管理系统,erp、orm、oa。

mybatis:

        专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全 的ORM框架,虽然程序员自己写sql,mybatis 也可以实现映射(输入映射、输出映射)。

应用场景:适用与需求变化较多的项目,比如:互联网项目。

  3.为什么要使用Mybatis?
  • 帮助程序员将数据存入到数据库中

  • 方便

  • 传统的JDBC代码太复杂了,简化,框架,自动化

  • 不用MyBatis也可以,技术没有高低之分

  • 优点:

    • 简单易学
    • 灵活
    • sql和代码的分离,提高了可维护性。
    • 提供映射标签,支持对象与数据库的orm字段关系映射
    • 提供对象关系映射标签,支持对象关系组建维护
    • 提供xml标签,支持编写动态sql
4.mybatis的核心配置文件 




    
        
            
            
                
                
                
                
            
        
    

mybatis工具类

//sqlSessionFactory --> sqlSession
public class MybatisUtils {

    static SqlSessionFactory sqlSessionFactory = null;

    static {
        try {
            //使用Mybatis第一步 :获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例.
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}
4.CRUD 1. namespace**

namespace中的包名要和Dao/Mapper接口的包名一致

2. select

选择,查询语句;

  • id:就是对应的namespace中的方法名;

  • resultType : Sql语句执行的返回值;

  • parameterType : 参数类型

//接口
public interface UserMapper {
    //查询所有用户
    public List getUserList();
    //插入用户
    public void addUser(User user);
}


//编写对应的mapper中的sql语句

    insert into user (id,name,password) values (#{id}, #{name}, #{password})



//测试
@Test
public void test2() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user  = new User(3,"黑子","666");
    mapper.addUser(user);
    //增删改一定要提交事务
    sqlSession.commit();

    //关闭sqlSession
    sqlSession.close();
}

 注意:增删改查一定要提交事务:

3. Insert

4. update
    
        update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}
        where id=#{id}
    


5. Delete 6. 万能Map

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

1.UserMapper接口 

//用万能Map插入用户
public void addUser2(Map map);

2.UserMapper.xml


    insert into user (id,name,password) values (#{userid},#{username},#{userpassword})

3.测试

@Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap map = new HashMap();
        map.put("userid",4);
        map.put("username","王虎");
        map.put("userpassword",789);
        mapper.addUser2(map);
        //提交事务
        sqlSession.commit();
        //关闭资源
        sqlSession.close();
    }

Map传递参数,直接在sql中取出key即可! 【parameter=“map”】

对象传递参数,直接在sql中取出对象的属性即可! 【parameter=“Object”】

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

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

7. 模糊查询 

1.Java代码执行的时候,传递通配符% %

List userList = mapper.getUserLike("%李%");

2.在sql拼接中使用通配符

select * from user where name like "%"#{value}"%"
5、配置解析 1. 核心配置文件
  • mybatis-config.xml

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

configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
2、环境配置(environments) 

MyBatis 可以配置成适应多种环境

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

学会使用配置多套运行环境!

MyBatis默认的事务管理器就是JDBC,连接池:POOLED

3、属性(properties) 

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

这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。【db.properties】

编写一个配置文件

db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?
useSSL=true&useUnicode=true&characterEncoding=utf8
username=root
password=Cc105481

 在核心配置文件中引入


    
    


可以直接引入外部文件
可以在其中增加一些属性配置
如果两个文件有同一字段,优先使用外部配置文件的!
4、类型别名(typeAliases)
类型别名是为 Java 类型设置一个短的名字。

存在的意义仅在于用来减少类完全限定名的冗余。

    
    
        
    

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

扫描实体类的包,他的默认别名就为这个类的类名,首字母小写!

 
    
        
    

在实体类比较少的时候,使用第一种方式。

如果实体类十分多,建议使用第二种方式。

第一种可以DIY别名,第二种则不行,如果非要改,需要在实体类(pojo)上增加@Alias注解

@Alias(“author”)
public class Author {

}

5、设置 

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

Settings

6、生命周期和作用域 

生命周期,和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqlSessionFactoryBuilder 

一旦创建了SqlSessionFactory,就不再需要它了 局部变量

mybatis运行流程SqlSessionFactory: 

可以想象为:数据库连接池 SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 因此SqlSessionFactory的最佳作用域是应用作用域。 最简单的就是使用 单例模式 或者静态单例模式

SqlSession 

连接到连接池的一个请求! SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 用完之后需要赶紧关闭,否则会占用资源 SqlSessionFactory

这里的每一个Mapper,就代表一个具体的业务!

 

 6、解决属性名和字段名不一致的问题

解决方法1:起别名

select id,name,pwd as password from mybatis.user where id = #{id}

 解决方法2:resultMap(结果集映射)


    
    
    
    


   
   select * from mybatis.user where id = #{id};
6、日志 6.1、日志工厂

如果一个数据库 *** 作,出现了异常,我们需要排错。日志就是最好的助手!

曾经:sout、debug

现在:日志工厂

SLF4J
LOG4J【掌握】
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING【掌握】
NO_LOGGING

在Mybatis中具体使用那个日志实现,在设置中设定!

STDOUT_LOGGING标准日志输出

在mybatis核心配置文件中,配置我们的日志!

日志配置

6.2、Log4j

Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
我们也可以控制每一条日志的输出格式
通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

 1.先导入log4j的包


    
    
        log4j
        log4j
        1.2.17
    

2.log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=【%c】-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=【%p】【%d{yy-MM-dd}】【%c】%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

3.配置log4j为日志实现


    

4.log4j的使用!直接测试运行刚才的查询

DEBUG [main] (LogFactory.java:105) - Logging initialized using ‘class org.apache.ibatis.logging.log4j.Log4jImpl’ adapter.
DEBUG [main] (LogFactory.java:105) - Logging initialized using ‘class org.apache.ibatis.logging.log4j.Log4jImpl’ adapter.
DEBUG [main] (PooledDataSource.java:353) - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] (PooledDataSource.java:353) - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] (PooledDataSource.java:353) - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] (PooledDataSource.java:353) - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] (JdbcTransaction.java:136) - Opening JDBC Connection
Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class iscom.mysql.cj.jdbc.Driver’. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
DEBUG [main] (PooledDataSource.java:424) - Created connection 2049051802.
DEBUG [main] (JdbcTransaction.java:100) - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7a220c9a]
DEBUG [main] (baseJdbcLogger.java:143) - ==> Preparing: /定义sql/ select * from mybatis.user where id = ?;
DEBUG [main] (baseJdbcLogger.java:143) - > Parameters: 1(Integer)
DEBUG [main] (baseJdbcLogger.java:143) - < Total: 1
User{id=1, name=‘狂神’, password=‘123456’}
DEBUG [main] (JdbcTransaction.java:122) - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7a220c9a]
DEBUG [main] (JdbcTransaction.java:90) - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7a220c9a]
DEBUG [main] (PooledDataSource.java:381) - Returned connection 2049051802 to pool.

Disconnected from the target VM, address: ‘127.0.0.1:58296’, transport: ‘socket’

Process finished with exit code 0
7、分页  (减少数据的处理量)

使用Limit分页

select * from user limit startIndex,pageSize

使用Mybatis实现分页,核心SQL 

接口

//分页
List getUserByLimit(Map map);

Mapper.xml



    select * from mybatis.user limit #{startIndex},#{pageSize}


测试

@Test
    public void getUserByLimit(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap map = new HashMap<>();
        map.put("startIndex",0);
        map.put("pageSize",2);

   List userList = mapper.getUserByLimit(map);
   for (User user : userList) {
       System.out.println(user);
   }
   sqlSession.close();
7.1、RowBounds分页

不再使用SQL实现分页

List getUserByRowBounds();

 mapper.xml

 
 
        select * from user 
        
        
        and id=#{id}
        
        
        and username like '%${username}%'
        
        
    
9.3foreach 

   
       id = #{id}
   
   
10、缓存(了解)  10.1、简介

查询 : 连接数据库,耗资源!
一次查询的结果,给他暂存在一个可以直接取到的地方!—>内存 : 缓存

我们再次查询相同数据的时候,直接走缓存,就不用走数据库了

 什么是缓存[Cache]?

    存在内存中的临时数据。

    将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,

    从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

为什么使用缓存?
    减少和数据库的交互次数,减少系统开销,提高系统效率。

什么样的数据能使用缓存?
    经常查询并且不经常改变的数据。

10.2、Mybatis缓存 

 MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
    默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
    二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    为了提扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

一级缓存 

一级缓存也叫本地缓存:

        SqlSession 与数据库同义词会话期间查询到的数据会放在本地缓存中。

        以后如果需要获取相同的数据,直接从缓存中拿,没有必要再去查询数据; 

缓存失效的情况: 

查询不同的东西

增删改 *** 作,可能会改变原来的数据,所以必定会刷新缓存!

查询不同的Mapper.xml

手动清理缓存! sqlsession.clearCache(); //手动清理缓存

小节:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段!

一级缓存就是一个Map。

二级缓存

 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
工作机制
    一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据会被保存到二级缓存中;
    新的会话查询信息,就可以从二级缓存中获取内容;
    不同的mapper查出的数据会放在自己对应的缓存(map)中;

 

开启全局缓存




在要使用二级缓存的Mapper中开启



也可以自定义参数


测试

    问题:我们需要将实体类序列化!否则就会报错

     java.io.NotSerializableException: com.rui.pojo.User

只要开启了二级缓存,在同一个Mapper下就有效 所有的数据都会先放在一级缓存中; 只有当会话提交,或者关闭的时候,才会提交到二级缓存中! 

总结 1.#{}和${}区别
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。
 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,
如果parameterType传输单个简单类型值,${}括号中只能是value。

能用#尽量用#

2.parameterType和resultType 
parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。
resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。
3.selectOne和selectList 

selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:

org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3

at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)

selectList可以查询一条或多条记录。

4.Mybatis分为三层 

  (1)API接口层:提供给外部使用的接口API

  (2)数据处理层:负责具体的SQL

  (3)基础支撑层:负责最基础的功能支撑,如连接管理,事务管理,配置加载和缓存处理

 5.SqlSession不是线程安全的

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5638410.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存