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</groupId>cn.example.testartifactId>mybatisversion>0.0.1-SNAPSHOTpackaging>war> dependencies> <!-- hibernate核心包 --> dependency> >org.hibernate>hibernate-core>5.2.12.Final> > mybatis核心包 >org.mybatis>3.1.1> 连接Mysql >mysql>mysql-connector-java>5.1.21打印日志 >org.slf4j>slf4j-api>1.7.5>slf4j-log4j12>log4j>1.2.17> project> ? ? 一、JDBC示例 package cn.jdbc; import java.sql.Connection; java.sql.DriverManager; java.sql.PreparedStatement; 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 ; } return conn; } public User getUserById(Integer Id) Exception { /** * 频繁的建立连接 */ Connection connection = getConnection(); PreparedStatement ps = ; ResultSet rs = ; { * 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); user; } } (Exception e) { e.printStackTrace(); }finally * 频繁的关闭连接 */ this.closeAll(rs,ps,connection); } ; } void closeAll(ResultSet rs,PreparedStatement ps,Connection conn) { { if(rs!=null && rs.isClosed()) { rs.close(); } } TODO: handle exception e.printStackTrace(); } if(ps!= ps.isClosed()) { ps.close(); } } if(conn!= conn.isClosed()) { conn.close(); } } e.printStackTrace(); } } static void main(String[] args) Exception { JdbcExample jdbc = 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在该例子中是适用所有的 数据表字段也就两个属性,大家自己建即可,这里就不贴了 User { private Integer Id; String userName; public Integer getId() { Id; } setId(Integer id) { Id = id; } String getUserName() { userName; } 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.Driverproperty> hibernate.connection.username : 连接数据库的用户名 ="hibernate.connection.username">root hibernate.connection.password : 连接数据库的密码 ="hibernate.connection.password">1234 hibernate.connection.url : 连接数据库的地址,路径 ="hibernate.connection.url">jdbc:mysql://localhost:3306/ssm> show_sql: 操作数据库时,会 向控制台打印sql语句 ="show_sql">true> format_sql: 打印sql语句前,会将sql语句先格式化 ="format_sql"> hbm2ddl.auto: 生成表结构的策略配置 update(最常用的取值): 如果当前数据库中不存在表结构,那么自动创建表结构. 如果存在表结构,并且表结构与实体一致,那么不做修改 如果存在表结构,并且表结构与实体不一致,那么会修改表结构.会保留原有列. create(很少):无论是否存在表结构.每次启动Hibernate都会重新创建表结构.(数据会丢失) create-drop(极少): 无论是否存在表结构.每次启动Hibernate都会重新创建表结构.每次Hibernate运行结束时,删除表结构. validate(很少):不会自动创建表结构.也不会自动维护表结构.Hibernate只校验表结构. 如果表结构不一致将会抛出异常. ="hbm2ddl.auto">update> 数据库方言配置 org.hibernate.dialect.MySQLDialect (选择最短的) ="hibernate.dialect">org.hibernate.dialect.MySQLDialect> hibernate.connection.autocommit: 事务自动提交 ="hibernate.connection.autocommit" 将Session与线程绑定=> 只有配置了该配置,才能使用getCurrentSession ="hibernate.current_session_context_class">thread> 引入ORM 映射文件 填写src之后的路径 mapping resource="cn/hibernate/User.hbm.xml"/> > > 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 ="cn.hibernate.User" table="user" dynamic-insert="true" dynamic-update="true"> <id>:定义了该属性到数据库表主键字段的映射。 name="userId":标识属性的名字; column="userId":表主键字段的名字,如果不填写与name一样; --> id ="Id"> <generator>:指定主键由什么生成,推荐使用uuid(随机生成唯一通用的表示符,实体类的ID必须是String), native(让数据库自动选择用什么生成(根据底层数据库的能力选择identity,sequence或hilo中的一种)), assigned(指用户手工填入,默认)。 --> generator ="native"/> id> <property>:为类定义一个持久化的javaBean风格的属性。 name="name":标识属性的名字,以小写字母开头; column="name":表主键字段的名字,如果不填写与name一样; update="true"/insert="true":默认为true,表示可以被更新或插入; ="userName" column="user_name" /> > > 3.HibernateExample.java cn.hibernate; org.hibernate.SessionFactory; org.hibernate.cfg.Configuration; HibernateExample { static SessionFactory sessionFactory; { { Configuration cfg = new Configuration().configure("hibernate.cfg.xml"); sessionFactory = cfg.buildSessionFactory(); } e.printStackTrace(); } } SessionFactory getSessionFactory() { sessionFactory; } } 4.TestHibernate.java org.hibernate.Session; 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 */ main(String[] args) { Session session = { session = HibernateExample.getSessionFactory().openSession(); User user = session.get(User.class,1); System.out.println(user.getUserName()); } if(session!=) { session.close(); } } } } 三、MyBatis示例 1.MyBatisExample示例 cn.mybatis; java.io.IOException; java.io.InputStream; org.apache.ibatis.io.Resources; org.apache.ibatis.session.SqlSession; org.apache.ibatis.session.SqlSessionFactory; org.apache.ibatis.session.SqlSessionFactoryBuilder; MyBatisExample { static SqlSessionFactory sqlSessionFactory = ; SqlSessionFactory getSqlSessionFactory() { InputStream is = if(sqlSessionFactory==) { String resource = "mybatis-config.xml"; { sqlSessionFactory = SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(resource)); sqlSessionFactory; } (IOException e) { e.printStackTrace(); } } sqlSessionFactory; } } 2.TestMyBatis.java org.apache.ibatis.session.SqlSession; TestMyBatis { main(String[] args) { SqlSession sqlSession = ; sqlSession = MyBatisExample.getSqlSessionFactory().openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.); User user = userMapper.getUserById(1); * 通过Main方法运行只能显示ID信息,不能显示userName的信息 * 这是因为resultType针对的字段和属性一致的情况,当数据表字段与JavaBean属性不一致时,要得到数据,需要使用resultMap System.out.println(user.getId()+"||"+user.getUserName()); } } 3.UserMapper.java interface UserMapper { User getUserById(Integer Id); } 4.UserMapper.xml 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 ="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" idcolumn="id" propertyresult ="user_name"="userName"resultMapmapper> 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包下起别名 --> typeAliasespackage ="cn.mybatis" > 对事务的管理和连接池的配置 --> environments default="development"> environment > transactionManager ="JDBC" /> dataSource ="POOLED"> ="driver" value="com.mysql.jdbc.Driver" /> ="url"="jdbc:mysql://localhost:3306/ssm" ="username"="root" ="password"="1234" dataSourceenvironment> environments> mapping 文件路径配置 mappers="cn/mybatis/UserMapper.xml" /> > > ? MyBatis还有很多有待研究的,说到这,不得不提一个增强版本的MyBatis 称之为MyBatis Plus 可无缝结合Spring+SpringMVC,而且增删改查也不需要写,只需继承一个类即可 参考官网:http://mp.baomidou.com/ 关于mybatis的逆向工程和动态代理,可以参考我的博客Java框架和MyBatis ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |