WebX实践指南_持久化(三)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 现在主流的持久化方案包括了IBatis以及Hibernate,两种方案的选型,这里不做阐述,因为笔者没用过Hibernate不敢随便评论。我选择IBatis是觉得自己写SQL做映射,很灵活,自己可以掌握SQL的设计。 参考:http://mybatis.org/mybatis-3/ MyBatis 是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBati

现在主流的持久化方案包括了IBatis以及Hibernate,两种方案的选型,这里不做阐述,因为笔者没用过Hibernate不敢随便评论。我选择IBatis是觉得自己写SQL做映射,很灵活,自己可以掌握SQL的设计。
参考:http://mybatis.org/mybatis-3/

MyBatis 是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得。
用xml文件构建SqlSessionFactory实例是非常简单的事情。推荐在这个配置中使用类路径资源(classpath resource),但你可以使用任何Reader实例,包括用文件路径或file://开头的url创建的实例。MyBatis有一个实用类—-Resources,它有很多方法,可以方便地从类路径及其它位置加载资源。

MyBatis入门指南

环境说明

基本的环境:需要MyBatis库以及JDBC的支持。

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.2.8</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.32</version>
    </dependency>

使用说明

平时使用过JDBC程序的同学,都有这样的映像,首先创建一个MySQL连接,然后执行对应语句,解析语句将对应的返回结果转成POJO对象。Ibatis设计的目的就是完成语句和对象的映射,使用的时候配置对应数据源和映射关系,使用相关接口来完成对应数据哭操作。下面看一下具体使用方法:

Ibatis配置说明

数据源

数据源包括环境和映文件,环境就是明确数据库的用户名、密码、要访的数据库地以及数据库访问的驱动;映射文件是SQL语句和对象的映射关系
cat ibatis.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>
    <properties>
        <property name="driver" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/test" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
    </properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="ibatis/example/User.xml"/>
    </mappers>
</configuration>

#### mapper映射管理
mapper里面需要配置的就是映关系也就是mapper,

注意mapper的resource地址。资源文件一般都放在resources目录下,对应的地址默认从resources下加载,因此使用相对地址即可。

下面看一下mapper文件 ibatis/example/User.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="org.mybatis.example.UserMapper">
      <select id="selectOneUser" resultType="User">
            select * from user where id = #{id}
      </select>
  </mapper>

### Ibatis使用流程
从配置文件中加载对应的数据源和Mapper

 String resource = "org/mybatis/example/mybatis-config.xml";
 InputStream inputStream = Resources.getResourceAsStream(resource);
 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

 SqlSession session = sqlSessionFactory.openSession();
 try {
    User user = (User) session.selectOne("org.mybatis.example.UserMapper.selectOneUser", 101);
 } finally {
     session.close();
 }

MyBatis相关概念

对象的生命周期

提示对象生命周期和依赖注入框架依赖注入框架可以创建线程安全的、基于事务的SqlSession,和映射器(mapper)并将它们直接注入到你的bean中,因此可以直接忽略它们的生命周期。如果对如何通过依赖注入框架来使用 MyBatis 感兴趣可以研究一下 MyBatis-Spring 或 MyBatis-Guice 两个子项目。

  • SqlSessionFactoryBuilder
    这个类可以被实例化、使用和丢弃,一旦创建了SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder实例的最佳范围是方法范围(也就是局部方法变量)。你可以用 SqlSessionFactoryBuilder来创建多个SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的 XML 解析资源开放给更重要的事情。

  • SqlSessionFactory

    SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。因此 SqlSessionFactory 的最佳范围是应用范围。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

  • SqlSession
    每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的范围是请求或方法范围。绝对不能将 SqlSession实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理范围中,比如 Serlvet 架构中的 HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的范围中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。下面的示例就是一个确保 SqlSession 关闭的标准模式:

    SqlSession session = sqlSessionFactory.openSession();
    try {
        // do work
    } finally {
        session.close();
    }

    在你的所有的代码中一致性地使用这种模式来保证所有数据库资源都能被正确地关闭。

  • 映射器实例(Mapper Instances)

    映射器是创建用来绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的。因此从技术层面讲,映射器实例的最大范围是和 SqlSession 相同的,因为它们都是从 SqlSession 里被请求的。尽管如此,映射器实例的最佳范围是方法范围。也就是说,映射器实例应该在调用它们的方法中被请求,用过之后即可废弃。并不需要显式地关闭映射器实例,尽管在整个请求范围(request scope)保持映射器实例也不会有什么问题,但是很快你会发现,像 SqlSession 一样,在这个范围上管理太多的资源的话会难于控制。所以要保持简单,最好把映射器放在方法范围(method scope)内。下面的示例就展示了这个实践:

    SqlSession session = sqlSessionFactory.openSession();
    try {
    BlogMapper mapper = session.getMapper(BlogMapper.class);
        // do work
    } finally {
    session.close();
    }

结合Spring

使用Spring需要在配置文件中添加applicationContext.xml文件,Spring容器启动时会

  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
     <property name="driverClassName" value="com.mysql.jdbc.Driver"/> 
     <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf8"/> 
     <property name="username" value="root"/> 
     <property name="password" value="password"/> 
  </bean> 

  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
     <!--dataSource属性指定要用到的连接池--> 
     <property name="dataSource" ref="dataSource"/> 
     <!--configLocation属性指定mybatis的核心配置文件--> 
     <property name="configLocation" value="config/Configuration.xml"/> 
  </bean>

使用的时候:

 private static ApplicationContext ctx;  
 static {  
        ctx = new ClassPathXmlApplicationContext("config/applicationContext.xml");  
}     

或者采用注解的方式来实现,建议使用注解,WebX是基于Spring的,可以直接支持Spring的这些特性,自己包装一下SqlSessionFactory。

@Service("sqlSessionFactory")
Class SqlSessionFactoryWraper {
    SqlSession openSession() {
    }
}

//使用
@Service("name=sqlSessionFactory")
private SqlSessionFactoryWraper sqlSessionFactory;

示例 DAO类

/**
 * Copyright 2006-2015 handu.com
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * 通用DAO实现类
 * @author Jinkai.Ma
 */
@Repository
public class Dao extends SqlSessionDaoSupport {

    /**
     * 设置工厂类
     *
     * @param sqlSessionFactory sql工厂类
     */
    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        super.setSqlSessionFactory(sqlSessionFactory);
    }

    /**
     * 插入
     *
     * @param prefix 前缀
     * @param key 关键字
     * @param object 参数对象
     */
    public void insert(String prefix, String key, Object object) {
        getSqlSession().insert(prefix + key, object);
    }

    /**
     * 修改
     *
     * @param prefix 前缀
     * @param key 关键字
     * @param object 参数对象
     */
    public void update(String prefix, String key, Object object) {
        getSqlSession().update(prefix + key, object);
    }

    /**
     * 删除
     *
     * @param prefix 前缀
     * @param key 关键字
     * @param id ID
     */
    public void delete(String prefix, String key, Serializable id) {
        getSqlSession().delete(prefix + key, id);
    }

    /**
     * 删除
     *
     * @param key 关键字
     * @param id ID
     */
    public void delete(String key, Serializable id) {
        getSqlSession().delete(key, id);
    }

    /**
     * 删除
     *
     * @param prefix 前缀
     * @param key 关键字
     * @param object 对象
     */
    public void delete(String prefix, String key, Object object) {
        getSqlSession().delete(prefix + key, object);
    }

    /**
     * 获取单条
     *
     * @param <T> 泛型
     * @param prefix 前缀
     * @param key 关键字
     * @param params 参数
     * @return T 泛型结果
     */
    public <T> T get(String prefix, String key, Object params) {
        return getSqlSession().selectOne(prefix + key, params);
    }

    /**
     * 获取集合
     *
     * @param <T> 泛型
     * @param prefix 前缀
     * @param key 关键字
     * @return T 泛型结果
     */
    public <T> List<T> getList(String prefix, String key) {
        return getSqlSession().selectList(prefix + key);
    }

    /**
     * 按查询条件获取集合
     *
     * @param <T> 泛型
     * @param prefix 前缀
     * @param key 关键字
     * @param params 参数
     * @return T 泛型结果
     */
    public <T> List<T> getList(String prefix, String key, Object params) {
        return getSqlSession().selectList(prefix + key, params);
    }

    /**
     * 获取数量
     *
     * @param prefix 前缀
     * @param key 关键字
     * @param params 参数
     * @return Integer
     */
    public Integer count(String prefix, String key, Object params) {
        return getSqlSession().selectOne(prefix + key, params);
    }

    /**
     * 分页
     *
     * @param prefix 前缀
     * @param pageKey 分页关键字
     * @param countKey 求数量关键字
     * @param params 参数
     * @param offset 偏移量
     * @param limit 限定数量
     * @return Object[]
     */
    public Object[] page(String prefix, String pageKey, String countKey, Object params, int offset, int limit) {
        return new Object[]{
                getSqlSession().selectList(prefix + pageKey, params, new RowBounds(offset, limit)),
                getSqlSession().selectOne(prefix + countKey, params)
        };
    }

    /**
     * 执行SQL语句
     *
     * @param sql SQL语句
     * @return boolean
     */
    public boolean executeSql(String sql) {
        try {
            return getSqlSession().getConnection().prepareStatement(sql).execute();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 执行查询SQL语句
     *
     * @param sql SQL语句
     * @return List<Map>
     */
    public List<Map> querySql(String sql) {
        List<Map> list = Lists.newArrayList();
        try {
            ResultSet rs = getSqlSession().getConnection().prepareStatement(sql,
                    ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_UPDATABLE).executeQuery();
            try {
                ResultSetMetaData rsm = rs.getMetaData(); //获得列集
                int col = rsm.getColumnCount(); //获得列的个数
                String[] colName = new String[col];
                //取结果集中的表头名称, 放在colName数组中
                for (int i = 0; i < col; i++) {
                    colName[i] = rsm.getColumnName(i + 1);
                }
                rs.beforeFirst();
                while (rs.next()) {
                    Map<String, String> map = Maps.newHashMap();
                    for (String aColName : colName) {
                        map.put(aColName, rs.getString(aColName));
                    }
                    list.add(map);
                }
            } catch (SQLException e) {
                e.printStackTrace();
                return null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }
}
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
缓存 Java 数据库
Spring框架(一) 底层核心原理解析
这个才是我们想要看的结果 ,我们可以简单分析一下 , userServiceBase的test1()方法也是有事务存在的 , 同时userServiceBase也是一个Bean , 它最终也会产生一个代理对象去当做一个Bean , 碎玉UserService而言 , 我要给userServiceBase这个属性去赋值 , 那么他肯定要从Spring容器中找到一个userServiceBase的一个Bean来赋值 , 所以他找到的就是Spring事务所产生的userServiceBase的代理对象 , 所以这个注解就是有用的
152 0
|
2月前
|
缓存 Java 数据库连接
Spring框架中的事件机制:深入理解与实践
Spring框架是一个广泛使用的Java企业级应用框架,提供了依赖注入、面向切面编程(AOP)、事务管理、Web应用程序开发等一系列功能。在Spring框架中,事件机制是一种重要的通信方式,它允许不同组件之间进行松耦合的通信,提高了应用程序的可维护性和可扩展性。本文将深入探讨Spring框架中的事件机制,包括不同类型的事件、底层原理、应用实践以及优缺点。
89 8
|
8月前
|
JSON 前端开发 Java
Spring第四课,MVC终章,应用分层的好处,总结
Spring第四课,MVC终章,应用分层的好处,总结
|
9月前
|
SQL 存储 开发框架
EntityFramework数据持久化复习资料6、EntityFramework引入
EntityFramework数据持久化复习资料6、EntityFramework引入
61 0
|
9月前
|
JavaScript 前端开发
new原理解析
本文深入解析了JavaScript中的new关键字,介绍了其作用、原理,并提供了一些代码示例来帮助读者更好地理解。通过对new关键字的详细解析,我们可以更好地理解JavaScript中对象实例的创建过程,从而更加灵活地运用new关键字来构建复杂的应用程序。
106 0
|
数据采集 Java 测试技术
APPcrawler基础原理解析及使用
appcrawler,使用Scala编程语言运行在JVM上,它是基于app爬虫的思想,逐渐形成了一种自动化测试方法称为“UI遍历”,其主导思想是尽可能多的去操作被测app的界面元素,每个元素至少操作一遍。
7930 0
|
Java Spring
Spring底层核心原理解析
Spring底层核心原理解析
221 0
|
JSON Java 数据格式
lowbit(x)的原理解析
快速学习lowbit(x)的原理解析
|
XML 缓存 NoSQL
撸完Spring源码,我开源了这个分布式缓存框架!!
撸完Spring源码,我开源了这个分布式缓存框架!!
193 0
撸完Spring源码,我开源了这个分布式缓存框架!!