• MyBatis+Hibernate+JDBC对比分析


    MyBatis目前作为持久层,用的最多,因为它符合互联网开发的变动性,实际开发中需求总会有这样的,那样的变动,MyBatis虽然没有Hibernate那么全自动化,而且对于开发人员的sql能力要求比较高,但是正是因为这样sql可以优化,业务也更容易扩展。

    hibernate对于sql能力不是特别强的开发人员,是一个很好的利器,而且hibernate更面向对象,hibernate不适合开发高并发高访问量的应用,很简单不能sql优化,每次查询基本都要全表扫描,即便是有hql,但是过多的使用hql,反而破坏Hibernate的封装性,实际开发多联表查多个字段信息,有的时候一张表十几个字段,信息,另外一个表十几个,在另外一个表又十几个,对于Hibernate而言是个不小的挑战,对于性能要求不高,响应速度较慢的应用,同一时间段访问人不多的应用,还是很不错的,可以大幅度提高开发效率

    OA办公,ERP等应用比较适合用Hibernate开发

    像门户网站,博客这样的,访问量比较大,不只是前端优化,后台也要优化,所谓的后台主要是指sql优化,当然还有Java代码方面

    MyBatis相对于JDBC而言,要好多了,至少它实现了解耦,sql语句和Java代码分离。

    对于目前我个人博客项目,它的逆向工程让我不再重复单表的增删改查,节省比较多的时间,当然mybatis,虽然对于需求变动大的项目而言是比较符合实际的需要的,但是它的不好之处也显现出来了,就是对于不同的数据库需要书写不同的sql语句,可移植性差,而且它的插件用不好的话,导致性能也会下降

    闲话不多说,贴一波个人编写的代码,温故而知新吧

    我这边演示是JDK8+MAVEN工程

    pom文件内容如下:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>cn.example.test</groupId>
      <artifactId>mybatis</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>war</packaging>
      
      <dependencies>
              <!-- hibernate核心包 -->
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-core</artifactId>
                <version>5.2.12.Final</version>
            </dependency>
            
              <!--mybatis核心包 -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.1.1</version>
            </dependency>
            
            <!-- 连接Mysql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.21</version>
            </dependency>
            
            <!--打印日志 -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.7.5</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>1.7.5</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
      
      </dependencies>
      
    </project>

    一、JDBC示例

    package cn.jdbc;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    
    public class JdbcExample {
        
        private static Connection getConnection() throws Exception {
            Connection conn = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                
                String url = "jdbc:mysql://localhost:3306/ssm";
                String username = "root";
                String password = "1234";
                conn = DriverManager.getConnection(url, username, password);
            
                
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            
                return null;
            }
            return conn;
                
            
        }
        
        public User getUserById(Integer Id) throws Exception {
            /**
             * 频繁的建立连接
             */
            Connection connection = getConnection();
            
            PreparedStatement ps = null;
            
            ResultSet rs = null;
            
            try {
                /**
                 * Java代码和sql混合,不解耦,随着项目扩大,工作量会成倍增加
                 */
                ps = connection.prepareStatement("select * from `user` where id=?");
                ps.setInt(1,Id);
                rs = ps.executeQuery();
            
                
                while(rs.next()) {
                    /**
                     * 指定获取的属性 
                     * 实际开发中数据表的字段多,想要获取十几二十几个字段信息,如下rs.getInt("字段名")等等一系列不知要写多少个,随着代码量的增大,更不利于排错
                     */
                    Integer id = rs.getInt("id");
                    String userName  = rs.getString("user_name");
                    User user = new User();
                    user.setId(id);
                    user.setUserName(userName);
                    
                    return user;
                    
                }
                        
                
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally {
                /**
                 * 频繁的关闭连接
                 */
                this.closeAll(rs, ps, connection);
            }
        
            return null;
            
        }
        
        private void closeAll(ResultSet rs,PreparedStatement ps,Connection conn) {
            
            try {
                
                if(rs!=null && rs.isClosed()) {
                    rs.close();
                }
                
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
            
            try {
                
                if(ps!=null && ps.isClosed()) {
                    ps.close();
                }
                
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
            
            try {
                
                if(conn!=null && conn.isClosed()) {
                    conn.close();
                }
                
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
            
                
        }
        
        public static void main(String[] args) throws Exception {
            JdbcExample jdbc = new JdbcExample();
            
            User user = jdbc.getUserById(1);
        
            System.out.println(user.getUserName());
        }
        
        /**
         * 从上述代码我们可以总结出Java连接JDBC的步骤
         * 1.加载驱动
         * 2.建立连接
         * 3.通过PreparedStatement执行sql
         * 4.由ResultSet返回结果集
         * 5.关闭连接
         * 
         * 使用传统的JDBC,存在如下问题:
         * 1.不解耦,JDBC和sql混合一起,当需求变动,既要改Java代码,又要修改sql语句,工作量十分大,而在实际项目中,需求是不断变化的
         * 2.频繁的建立连接,关闭连接,虽然后面有连接池,或者是将其封装成一个Utils,不过代码量依然会很大
         * 
         * 说明:实际开发中并不用它,但是作为开发者必须要知道技术的应用场景和利弊,这样才能在开发中游刃有余
         */
        
    
    }

    JavaBean

    说明:JavaBean在该例子中是适用所有的

    数据表字段也就两个属性,大家自己建即可,这里就不贴了

    package cn.jdbc;
    
    public class User {
        private Integer Id;
        private String userName;
        public Integer getId() {
            return Id;
        }
        public void setId(Integer id) {
            Id = id;
        }
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        
        
    }

    二、Hibernate示例

    1.hibernate.cfg.xml主配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    
    <hibernate-configuration>
        <session-factory>
            <!-- property 元素用于配置Hibernate中的属性
                键:值 
              -->
              <!-- hibernate.connection.driver_class : 连接数据库的驱动  -->
            <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    
    
              <!-- hibernate.connection.username : 连接数据库的用户名 -->
            <property name="hibernate.connection.username">root</property>
    
    
              <!-- hibernate.connection.password : 连接数据库的密码 -->
            <property name="hibernate.connection.password">1234</property>
    
    
              <!-- hibernate.connection.url : 连接数据库的地址,路径 -->
            <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/ssm</property>
    
    
    
            <!-- show_sql: 操作数据库时,会 向控制台打印sql语句 -->
            <property name="show_sql">true</property>
    
        
    
            <!-- format_sql: 打印sql语句前,会将sql语句先格式化  -->
            <property name="format_sql">true</property>
    
    
          
    
            <!-- hbm2ddl.auto: 生成表结构的策略配置
                 update(最常用的取值): 如果当前数据库中不存在表结构,那么自动创建表结构. 
                         如果存在表结构,并且表结构与实体一致,那么不做修改
                         如果存在表结构,并且表结构与实体不一致,那么会修改表结构.会保留原有列.
                 create(很少):无论是否存在表结构.每次启动Hibernate都会重新创建表结构.(数据会丢失)
                 create-drop(极少): 无论是否存在表结构.每次启动Hibernate都会重新创建表结构.每次Hibernate运行结束时,删除表结构.
                 validate(很少):不会自动创建表结构.也不会自动维护表结构.Hibernate只校验表结构. 如果表结构不一致将会抛出异常.
              -->
            <property name="hbm2ddl.auto">update</property>
    
    
            <!-- 数据库方言配置 
             org.hibernate.dialect.MySQLDialect (选择最短的)
             -->
            <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    
    
           
    
            <!-- hibernate.connection.autocommit: 事务自动提交  -->
            <property name="hibernate.connection.autocommit">true</property>
    
    
    
            <!-- 将Session与线程绑定=> 只有配置了该配置,才能使用getCurrentSession -->
            <property name="hibernate.current_session_context_class">thread</property>
    
    
    
    
            <!-- 引入ORM 映射文件 
                填写src之后的路径
             -->
            <mapping resource="cn/hibernate/User.hbm.xml"/>
        </session-factory>
    </hibernate-configuration>

    2.User.hbm.xml文件

    <hibernate-mapping>    
        
        <!--     
            <class>:使用class元素定义一个持久化类。    
            name="cn.javass.user.vo.UserModel":持久化类的java全限定名;    
            table="tbl_user":对应数据库表名;    
            mutable="true":默认为true,设置为false时则不可以被应用程序更新或删除;    
            dynamic-insert="false":默认为false,动态修改那些有改变过的字段,而不用修改所有字段;    
            dynamic-update="false":默认为false,动态插入非空值字段;    
            select-before-update="false":默认为false,在修改之前先做一次查询,与用户的值进行对比,有变化都会真正更新;    
           
         -->    
        <class name="cn.hibernate.User" table="user" dynamic-insert="true" dynamic-update="true">    
                
            <!--     
                <id>:定义了该属性到数据库表主键字段的映射。    
                name="userId":标识属性的名字;    
                column="userId":表主键字段的名字,如果不填写与name一样;    
             -->    
            <id name="Id">    
                <!-- <generator>:指定主键由什么生成,推荐使用uuid(随机生成唯一通用的表示符,实体类的ID必须是String),  
                                   native(让数据库自动选择用什么生成(根据底层数据库的能力选择identity,sequence或hilo中的一种)),  
                                   assigned(指用户手工填入,默认)。 -->    
                <generator class="native"/>    
            </id>    
    
            <!--     
                <property>:为类定义一个持久化的javaBean风格的属性。    
                name="name":标识属性的名字,以小写字母开头;    
                column="name":表主键字段的名字,如果不填写与name一样;    
                update="true"/insert="true":默认为true,表示可以被更新或插入;    
             -->    
            <property name="userName" column="user_name" />    
                 
        </class> 
    </hibernate-mapping>

    3.HibernateExample.java

    package cn.hibernate;
    
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    public class HibernateExample {
    
        private static SessionFactory sessionFactory;
        
        static {
            
        
            try {
                Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
                
                sessionFactory = cfg.buildSessionFactory();
                
            } catch (Exception e) {
                // TODO: handle exception
            
                e.printStackTrace();
            }
        }
        
        public static SessionFactory getSessionFactory() {
            
            return sessionFactory;            
        }
        
        
        
        
        
        
    }

    4.TestHibernate.java

    package cn.hibernate;
    
    import org.hibernate.Session;
    
    public class TestHibertnate {
        
        /**
         * hibernate流程
         *1.通过Configuration创建SessionFactory
         *2.通过SessionFactory创建Session
         *3.通过Session打开openSession
         *4.通过session调用方法
         *
         *
         *openSession和getCurrentSession的区别
         *openSession创建session时autoCloseSessionEnabled参数为false,即在事物结束后不会自动关闭session,需要手动关闭,如果不关闭将导致session关联的数据库连接无法释放,最后资源耗尽而使程序挂掉。              
         *getCurrentSession创建session时autoCloseSessionEnabled,flushBeforeCompletionEnabled都为true,并且session会同sessionFactory组成一个map以sessionFactory为主键绑定到当前线程。
         * @param args
         */
        public static void main(String[] args) {
            
            Session session = null;
            
            try {
                session = HibernateExample.getSessionFactory().openSession();
                
                User user = session.get(User.class, 1);
                System.out.println(user.getUserName());
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }finally {
                if(session!=null) {
                    session.close();
                }
            }
            
            
        }
    }

    三、MyBatis示例

    1.MyBatisExample示例

    package cn.mybatis;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    public class MyBatisExample {
    
        private static SqlSessionFactory sqlSessionFactory = null;
        
        public static SqlSessionFactory getSqlSessionFactory() {
            InputStream is  = null;
            if(sqlSessionFactory==null) {
                
                String resource = "mybatis-config.xml";
                try {
                    sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(resource));
                    return sqlSessionFactory;
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }            
        
            }
        
            return sqlSessionFactory;
        }
            
        
        
    
    }

    2.TestMyBatis.java

    package cn.mybatis;
    
    import org.apache.ibatis.session.SqlSession;
    
    public class TestMyBatis {
    
        public static void main(String[] args) {
            SqlSession sqlSession = null;
            sqlSession = MyBatisExample.getSqlSessionFactory().openSession();
            
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User user = userMapper.getUserById(1);
            /**
             * 通过Main方法运行只能显示ID信息,不能显示userName的信息
             * 这是因为resultType针对的字段和属性一致的情况,当数据表字段与JavaBean属性不一致时,要得到数据,需要使用resultMap
             */
            System.out.println(user.getId()+"||"+user.getUserName());
    
        }
    }

    3.UserMapper.java

    package cn.mybatis;
    
    public interface UserMapper {
    
        
        User getUserById(Integer Id);
    }

    4.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="cn.mybatis.UserMapper">
    
        <!-- 
        id 必须与对应接口方法一致
        parameterType 参数类型可以是Map,String,Integer等等一大堆,但是必须要指定
        resultType 适用场景:数据表字段和JavaBean实体属性一致
        resultMap 适用场景:数据表字段和JavaBean实体属性不一致
        
         -->
        
        <!--     <select id="getUserById" parameterType="Integer" resultType="cn.mybatis.User">
            select id,user_name from `user` where id=#{Id}
        </select> -->
        
        <select id="getUserById" parameterType="Integer" resultMap="users">
            select id,user_name from `user` where id=#{Id}
        </select>    
        
        <!-- 
        column对应数据表字段
        property对应JavaBean属性
        type 通常指返回类型 一般要写全限定名 不过只要在mybatis-config.xml配置别名扫描就不要写全名了
         -->
         
        <resultMap type="User" id="users">
        <id column="id" property="Id"/>
        <result column="user_name" property="userName"/>
        </resultMap>
    
    </mapper>

    5.mybatis-config.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>
        
        <!-- 给cn.mybatis包下起别名 -->
        <typeAliases>
        <package name="cn.mybatis" />
        </typeAliases>
    
         <!-- 对事务的管理和连接池的配置 -->  
        <environments default="development">  
            <environment id="development">  
                <transactionManager type="JDBC" />  
                <dataSource type="POOLED">  
                    <property name="driver" value="com.mysql.jdbc.Driver" />  
                    <property name="url" value="jdbc:mysql://localhost:3306/ssm" />  
                    <property name="username" value="root" />  
                    <property name="password" value="1234" />  
                </dataSource>  
            </environment>  
        </environments>  
          
        <!-- mapping 文件路径配置 -->  
        <mappers>  
            <mapper resource="cn/mybatis/UserMapper.xml" />  
        </mappers>  
    
    </configuration>  

    MyBatis还有很多有待研究的,说到这,不得不提一个增强版本的MyBatis 称之为MyBatis Plus 可无缝结合Spring+SpringMVC,而且增删改查也不需要写,只需继承一个类即可

    参考官网:http://mp.baomidou.com/

    关于mybatis的逆向工程和动态代理,可以参考我的博客Java框架和MyBatis

  • 相关阅读:
    Apollo的Oracle适配改动
    尝试Java,从入门到Kotlin(下)
    尝试Java,从入门到Kotlin(上)
    RabbitMQ权限控制原理
    一文彻底掌握二叉查找树(多组动图)(史上最全总结)
    图解:深度优先搜索与广度优先搜索及其六大应用
    图解:如何理解与实现散列表
    图解:什么是“图”?
    查找算法系列文(一)一文入门二叉树
    线性表(数组、链表、队列、栈)详细总结
  • 原文地址:https://www.cnblogs.com/youcong/p/8719778.html
Copyright © 2020-2023  润新知