一、Mybatis入门

一、单独使用jdbc编程问题总结

  创建JDBC连接数据库

  • 创建resources\jdbc.properties
db.username=root
db.password=root
db.jdbcUrl=jdbc:mysql:///mybatisdb?useSSL=false&serverTimezone=UTC
db.driverClass=com.mysql.jdbc.Driver
  • JDBC操作数据库
public class JDBC_Demo {
    private String userName = null;
    private String password = null;
    private String jdbcUrl = null;
    private String driverClass = null;


    private ResultSet resultSet =null;
    private PreparedStatement preparedStatement  =null;
    private Connection connection =null;

    /**
     * 获取配置文件中的数据库信息
     */
    {
        ClassLoader classLoader2 = this.getClass().getClassLoader();
        InputStream resourceAsStream = classLoader2.getResourceAsStream("jdbc.properties");
        Properties properties = new Properties();
        try {
            properties.load(resourceAsStream);
            userName = properties.getProperty("db.username");
            password = properties.getProperty("db.password");
            jdbcUrl = properties.getProperty("db.jdbcUrl");
            driverClass = properties.getProperty("db.driverClass");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Test
    public void jdbcDemo () throws ClassNotFoundException {

        try {
            //第一步:加载数据库驱动
            Class.forName(driverClass);
            //第二步:通过驱动管理类获取数据库链接
            connection = DriverManager.getConnection(jdbcUrl, userName, password);
            //第三步:定义sql语句 ?表示占位符
            String sql = "select * from items where id = ?";
            //第四步:获取预处理statement
            preparedStatement = connection.prepareStatement(sql);
            //第五步:设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
            preparedStatement.setInt(1, 1);
            //第六步:向数据库发出sql执行查询,查询出结果集
            resultSet = preparedStatement.executeQuery();
            //第七步:遍历查询结果集
            while (resultSet.next()) {
                System.out.println(resultSet.getInt("id") + "  "
                        + resultSet.getString("name"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //第八步:释放资源
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • DriverManager类作用于java程序和JDBC驱动之间,用于检查所加载的驱动程序是否可以建立连接然后通过getConnction()方法根据数据库的URL、用户名和密码,创建一个JDBC Connection 对象

  • Statement对象,Statement类的主要作用用于执行静态的SQL语句并且返回生成结果对象,通过Connection对象的createStatement()方法可以创建一个Statement对象。

  • 调用Statement对象的相关方法执行响应的语句,execuUpdate()更新。

  • 通过Statement的execuQuery()方法进行数据查询,查询结果保存在ResulSet对象中,通过ResulSet对象的next()方法。使指针指向下一行。

上边使用jdbc的原始方法(未经封装)实现了查询数据库表记录的操作。

1.1、jdbc编程步骤

  1. 加载数据库驱动

  2. 创建并获取数据库链接

  3. 创建jdbc statement对象

  4. 设置sql语句

  5. 设置sql语句中的参数(使用preparedStatement)

  6. 通过statement执行sql并获取结果

  7. 对sql执行结果进行解析处理

  8. 释放资源(resultSet、preparedstatement、connection)

1.2、jdbc问题总结如下

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

二、MyBatis介绍

  MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatis对ibatis进行一些改进。

  MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码

  Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

2.1、Mybatis架构

  1. mybatis配置

    • mybatis-config.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。

    • mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。mapper.xml文件需要在mybatis-config.xml中加载。

  2. 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂。

  3. 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

  4. mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。

  5. Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。

  6. Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

  7. Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

2.2、mybatis下载

  mybaits的代码由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>

2.3、Mybatis数据准备

CREATE DATABASE `mybatisdb` ;
USE `mybatisdb`;
DROP TABLE IF EXISTS `items`;

CREATE TABLE `items` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(32) NOT NULL COMMENT '商品名称',
  `price` FLOAT(10,1) NOT NULL COMMENT '商品定价',
  `detail` TEXT COMMENT '商品描述',
  `createtime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '订单创建时间',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;


INSERT  INTO `items`(`id`,`name`,`price`,`detail`,`createtime`) 
VALUES (1,'台式机',3000.0,'该电脑质量非常好!!!!','2015-02-03 13:22:53'),
(2,'笔记本',6000.0,'笔记本性能好,质量好!!!!!','2015-02-09 13:22:57'),
(3,'背包',200.0,'名牌背包,容量大质量好!!!!','2015-02-06 13:23:02');

DROP TABLE IF EXISTS `orderdetail`;

CREATE TABLE `orderdetail` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `orders_id` INT(11) NOT NULL COMMENT '订单id',
  `items_id` INT(11) NOT NULL COMMENT '商品id',
  `items_num` INT(11) DEFAULT NULL COMMENT '商品购买数量',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

INSERT  INTO `orderdetail`(`id`,`orders_id`,`items_id`,`items_num`) 
VALUES (1,1,1,1),(2,2,2,2),(3,4,3,4),(4,4,2,3);

DROP TABLE IF EXISTS `orders`;

CREATE TABLE `orders` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `user_id` INT(11) NOT NULL COMMENT '下单用户id',
  `number` VARCHAR(32) NOT NULL COMMENT '订单号',
  `createtime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓璁㈠崟鏃堕棿',
  `note` VARCHAR(100) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

INSERT  INTO `orders`(`id`,`user_id`,`number`,`createtime`,`note`) 
VALUES (3,1,'1000010','2015-02-04 13:22:35',NULL),
(4,1,'1000011','2015-02-03 13:22:41',NULL),
(2,10,'1000012','2015-02-12 16:13:23',NULL);

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(32) NOT NULL COMMENT '用户名称',
  `birthday` DATE DEFAULT NULL COMMENT '生日',
  `sex` CHAR(1) DEFAULT NULL COMMENT '性别',
  `address` VARCHAR(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;

INSERT  INTO `user`(`id`,`username`,`birthday`,`sex`,`address`)
VALUES 
(1,'王五',NULL,'2',NULL),
(2,'张三','2014-07-10','1','北京市'),
(3,'张小明',NULL,'1','河南郑州')
 
 

三、Mybatis入门程序

实现以下功能:

  • 根据用户id查询一个用户信息

  • 根据用户名称模糊查询用户信息列表

  • 添加用户

  • 更新用户

  • 删除用户

3.1、创建Maven工程,导入依赖

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
      
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

3.2、创建配置文件

  • 在classpath下创建log4j.properties如下:
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

  mybatis默认使用log4j作为输出日志信息。

  • 在classpath下创建mybatis-config_01.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>
    <!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理-->
            <transactionManager type="JDBC"/>
            <!-- 数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql:///mybatisdb?useSSL=false&amp;serverTimezone=UTC"/>
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
</configuration>

  mybatis-config_01.xml是mybatis核心配置文件,上边文件的配置内容为数据源、事务管理。

  IDEA方法参考:https://www.cnblogs.com/jdy1022/p/13618378.html

3.3、创建po类

  Po类作为mybatis进行sql映射使用,po类通常与数据库表对应,User.java如下:

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User implements Serializable {
    private String id;
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址
    private List<Orders> orders;
}

3.4、创建映射配置文件

  • 在classpath下的sqlmap目录下创建sql映射文件Users.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="user">

    <!--user表字段-->
    <sql id="sqlColumnsForUserTable">
        id,username,sex,birthday,address
    </sql>


    <!--结果集-->
    <resultMap type="com.jdy.mybatis2020.bean.User" id="userMap">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="sex" property="sex"/>
        <result column="birthday" property="birthday"/>
        <result column="address" property="address"/>
    </resultMap>


    <!--条件-->
    <sql id="sqlConditions">
        <if test="username != null and '' != username">
            <![CDATA[ AND username = #{username} ]]>
        </if>
        <if test="sex != null and '' != sex">
            <![CDATA[ AND sex  LIKE CONCAT('%','${sex}','%' ) ]]>
        </if>
        <if test="address != null and '' != address">
            <![CDATA[ AND  address = #{address} ]]>
        </if>
        <if test="birthday != null and '' != birthday">
            <![CDATA[ AND birthday > DATE_FORMAT(#{birthday},'%Y-%m-%d') ]]>
        </if>
    </sql>


    <!-- 根据id获取用户信息 -->
    <select id="findUserById"  resultType="com.jdy.mybatis2020.bean.User">
        select
        <include refid="sqlColumnsForUserTable"/>
        from user where id = #{id};
    </select>


    <!-- 模糊查询查询用户 -->
    <select id="findUserLikeUsername"  resultType="com.jdy.mybatis2020.bean.User">
        select <include refid="sqlColumnsForUserTable"/>
        from user where username like '%${value}%';
    </select>


    <!-- 添加用户 -->
    <insert id="insertUser" parameterType="com.jdy.mybatis2020.bean.User">
        <!-- selectKey将主键返回,需要再返回 -->
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
            select LAST_INSERT_ID();
        </selectKey>
        insert into user(<include refid="sqlColumnsForUserTable"/>)
        values(#{id},#{username},#{sex},#{birthday},#{address});
    </insert>


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


    <!-- 更新用户 -->
    <update id="updateUser" parameterType="com.jdy.mybatis2020.bean.User">
        update user
        <set>
            <if test="username != null">
                username = #{username},
            </if>
            <if test="birthday != null">
                birthday = #{birthday},
            </if>
            <if test="sex != null">
                sex = #{sex},
            </if>
            <if test="address != null">
                address = #{address},
            </if>
        </set>
        where id=#{id}
    </update>

</mapper>
  • namespace命名空间,用于隔离sql语句,后面会讲另一层非常重要的作用。

  • parameterType:定义输入到sql中的映射类型,#{id}表示使用preparedstatement设置占位符号并将输入变量id传到sql。mybatis通过ognl从输入对象中获取参数值拼接在sql中。

  • resultType:定义结果映射类型。mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。

3.5、加载映射文件

  mybatis框架需要加载映射文件,把user.xml添加在mybatis-config_01.xml,如下:

    <mappers>
        <mapper resource="sqlmap/user.xml"/>
    </mappers>

3.6、测试

  • 创建SqlSessionFactory的工具类
public static SqlSessionFactory  createFactory(String resource){
        try {
            // 使用SqlSessionFactoryBuilder从xml配置文件中创建SqlSessionFactory
            InputStream inputStream = Resources.getResourceAsStream(resource);
            return  new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
  • 测试类:Test_00
public class Test_00 {

    public static final String RESOURCE = "mybatis-config/mybatis-config_01.xml";

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void createFactory(){
        sqlSessionFactory = SqlSessionFactoryUtil.createFactory(RESOURCE);
    }
    /**
     * 查询数据
     */
    @Test
    public void test_Method00() {
        // 数据库会话实例,一个SqlSession对象代表和数据库的一次会话
        SqlSession sqlSession = null;
        try {
            // 创建数据库会话实例sqlSession
            sqlSession = sqlSessionFactory.openSession();
            // 查询单个记录,根据用户id查询用户信息
            User user = sqlSession.selectOne("user.findUserById", "1");
            // 模糊查询
            List<User> users = sqlSession.selectList("user.findUserLikeUsername", "小");
            // 输出用户信息
            System.out.println(user);
            System.out.println(users);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

    /**
     * 添加数据
     */
    @Test
    public void test_Method01() {
        SqlSession sqlSession = null;
        try {
            // 创建数据库会话实例sqlSession
            sqlSession = sqlSessionFactory.openSession();
            // 添加用户信息
            User user = new User();
            user.setUsername("ws");
            user.setAddress("陕西西安");
            user.setSex("1");
            user.setBirthday(new Date());
            sqlSession.insert("user.insertUser", user);
            //提交事务
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

    /**
     * 删除数据
     */
    @Test
    public void test_Method02() {
        // 数据库会话实例
        SqlSession sqlSession = null;
        try {
            // 创建数据库会话实例sqlSession
            sqlSession = sqlSessionFactory.openSession();
            // 删除用户
            sqlSession.delete("user.deleteUserById", "3");
            // 提交事务
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

    /**
     * 修改数据
     */

    @Test
    public void test_Method03() {
        // 数据库会话实例
        SqlSession sqlSession = null;
        try {
            // 创建数据库会话实例sqlSession
            sqlSession = sqlSessionFactory.openSession();
            // 添加用户信息
            User user = new User();
            user.setId(29);
            user.setUsername("jdy");
            user.setAddress("sxxn");
            user.setSex("1");
            user.setBirthday(new Date());
            sqlSession.update("user.updateUser", user);
            // 提交事务
            sqlSession.commit();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}

#{}和${}的区别?

#{}是预编译处理,$ {}是字符串替换。

  • #{}表示一个占位符号#{}是预编译处理,预编译是提前对SQL语句进行预编译,而其后注入的参数将不会再进行SQL编译。SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译成了恶意的执行操作。而预编译机制则可以很好的防止SQL注入。#{parm}传入的数据都当成一个字符串,会对自动传入的数据加一个双引号

  • ${}表示拼接sql串,是字符串替换,MyBatis在处理时,它会将sql中的{ }替换为变量的值,传入的数据不会加两边加上单引号${param}传递的参数会被当成sql语句中的一部分,比如传递表名,字段名

3.7、mysql自增主键返回  

  若数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),则可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上

<insert id="insertUserNew" parameterType="com.jdy.mybatis2020.bean.User" useGeneratedKeys="true" keyProperty="id">
        insert into user(username,birthday,sex,address)values(#{username},#{birthday},#{sex},#{address})
</insert>

  而对于不支持自增型主键的数据库(例如Oracle),Oracle使用序列来模拟自增;每次插入的数据的主键是从序列中拿到的值。可以使用 selectKey 子元素(同时支持mysql):selectKey 元素将会首先运行, id 会被设置, 然后插入语句会被调用

  通过修改sql映射文件,可以将mysql自增主键返回:

<!-- 添加用户 -->
    <insert id="insertUser" parameterType="com.jdy.mybaties2020.bean.User">
        <!-- selectKey将主键返回,需要再返回 -->
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
            select LAST_INSERT_ID()
        </selectKey>
        insert into user(username,birthday,sex,address)values(#{username},#{birthday},#{sex},#{address})
    </insert>

  添加selectKey实现将主键返回

    • keyProperty指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性。

    • order:取值BEFORE|AFTER。selectKey的执行顺序,是相对与insert语句来说,由于mysql的自增原理,执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after。

    • resultType:返回的主键是什么类型。

    • LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。

  Mysql使用 uuid实现主键

<!--需要增加通过select uuid()得到uuid值-->
<!--注意这里使用的order是“BEFORE”-->
<insert  id="insertUser" parameterType="com.jdy.mybaties2020.bean.User">
  <selectKey resultType="java.lang.String" order="BEFORE" keyProperty="id">
        select uuid()
  </selectKey>
insert into user(id,username,birthday,sex,address) 
         values(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
  1. 为什么要使用MyBatis?

    • MyBatis是一个半自动化的持久化层框架。

    • 与JDBC相比,JDBC的SQL夹在Java代码块里,耦合度高导致硬编码内伤, 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见。

    • 与Hibernate和JPA相比,Hibernate和JPA 操作长难复杂SQL,对于而言处理也不容易,Hibernate内部自动生产的SQL,不容易做特殊优化,JPA基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难,导致数据库性能下降。

    • 对开发人员而言,核心sql还是需要自己优化,MyBatis 将sql和java 编码分开,功能边界清晰,一个专注业务、一个专注数据 。

  2. Mybatis与hibernate不同?

    • Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句,不过mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

    • Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

    • Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。

    • 总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。 

posted @ 2020-09-21 09:42  jingdy  阅读(117)  评论(0编辑  收藏  举报