MyBatis-16MyBatis动态SQL之【支持多种数据库】

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: MyBatis-16MyBatis动态SQL之【支持多种数据库】

概述


MyBatis-15MyBatis动态SQL之【bind】 bind标签并不能解决更换数据库带来的所有问题。 那么还有没其他的方式来支持不同的数据库呢 ?


答案是 使用if标签以及由MyBatis提供的databaseIdProvider数据库厂商标识配置


MyBatis可以根据不同的数据库厂商执行不同的SQL,这种多厂商的支持是基于映射语句中的databaseId属性。 MyBatis会加载不带databaseId属性和带有匹配当前数据库databaseId属性的所有语句。 如果同时找到了带有databaseId和不带databaseId的相同语句,则不带databaseId的将被舍弃。


配置


1.MyBatis全局配置文件增加


为了支持多厂商数据库,需要在MyBatis全局配置文件中加入databaseIdProvider配置 <databaseIdProvider type="DB_VENDOR"/>


也可以通过实现接口 org.apache.ibatis.mapping.DatabaseIdProvider 并在 mybatis-config.xml 中注册来构建自己的 DatabaseIdProvider


DB_VENDOR会通过DatabaseMetaData#getDatabaseProductName()返回的字符串进行设置, 通常情况下这个字符串比较长而且相同产品的不同版本会返回不同的值,通常会设置属性别名使其变短。

    <!-- 多数据库支持 -->
    <databaseIdProvider type="DB_VENDOR">
        <property  name ="SQL  Server" value="sqlserver"/>
        <property  name ="DB2" value ="db2"/>
        <property  name ="Oracle" value ="oracle"/>
        <property  name ="MySQL" value ="mysql"/>
        <property  name ="PostgreSQL" value ="postgresql"/>
        <property  name ="Derby" value ="derby"/>
        <property  name ="HSQL" value ="hsqldb"/>
        <property  name ="H2" value ="h2"/>
    </databaseIdProvider>


上述列举了常见的数据库产品名称,在有property配置时,databaseId将被设置为第一个能匹配数据库产品名称的属性键对应的值,如果没有匹配则置为null .


DB_VENDOR的匹配策略为DatabaseMetaData#getDatabaseProductName()返回的字符串包含property中name部分的值即可匹配。


数据库产品名一般由选择的当前数据库的JDBC驱动所决定,只要找到对应数据库DatabaseMetaData的实现类,一般在getDatabaseProductName()方法中就可以直接找到该值。

任何情况下都可以通过调用DatabaseMetaData#getDatabaseProductName()来获取具体的值


完整的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>
    <!-- 引入外部属性文件 ,必须放在第一位-->
    <properties resource="db.properties"/>
    <settings>
        <!-- 通过logImpl属性指定使用LOG4J输出日志,mybatis默认使用log4j作为输出日志信息。 -->
        <setting name="logImpl" value="LOG4J" />
        <!-- 通过配置这个属性为true可以自动将下画线方式命名的数据库列映射到java对象驼峰式命名属性中
        <setting name="mapUnderscoreToCamelCase" value="true"/>
         -->
    </settings>
    <!-- typeAliases元素下配置了一个包的别名,通常确定一个类的时候需要使用全限定名,
        比如 com.artisan.mybatis.simple.mapper.model.Country
    -->
    <typeAliases>
        <package name="com.artisan.mybatis.simple.model" />
    </typeAliases>
    <!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理-->
            <transactionManager type="JDBC"/>
            <!-- 数据库连接池-->
            <dataSource type="UNPOOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    <!-- 多数据库支持 -->
    <databaseIdProvider  type="DB_VENDOR" >
        <property  name ="SQL  Server" value="sqlserver"/>
        <property  name ="DB2" value ="db2"/>
        <property  name ="Oracle" value ="oracle"/>
        <property  name ="MySQL" value ="mysql"/>
        <property  name ="PostgreSQL" value ="postgresql"/>
        <property  name ="Derby" value ="derby"/>
        <property  name ="HSQL" value ="hsqldb"/>
        <property  name ="H2" value ="h2"/>
    </databaseIdProvider>
    <mappers>
        <!-- 配置具体的mapper -->
        <mapper resource="com/artisan/mybatis/simple/mapper/CountryMapper.xml" />
        <!-- 逐一配置,比较繁琐,容易遗漏,接口方式不推荐
        <mapper resource="com/artisan/mybatis/xml/mapper/UserMapper.xml"/>
        <mapper resource="com/artisan/mybatis/xml/mapper/UserRoleMapper.xml"/>
        <mapper resource="com/artisan/mybatis/xml/mapper/RoleMapper.xml"/>
        <mapper resource="com/artisan/mybatis/xml/mapper/PrivilegeMapper.xml"/>
        <mapper resource="com/artisan/mybatis/xml/mapper/RolePrivilegeMapper.xml"/>
         -->
        <!-- 推荐:通过包的方式配置,mybatis会先查找对应包下的所有的接口 -->
        <package name="com.artisan.mybatis.xml.mapper"/>
    </mappers>
</configuration>


注意databaseIdProvider节点的位置。


2.映射文件中的标签调整包含databaseId属性

除了增加上述配置之外,映射文件也需要调整,关键在于下面几个映射文件的标签中含有的databaseId属性


  • select
  • insert
  • update
  • delete
  • selectKey
  • sql

示例


20180428040311282.png


举个简单的例子,查询当前时间

我们知道 mysql中的语句为

select now() from dual


oracle中为

select sysdate from dual


增加个查询当前时间的接口


结合mybatis全局配置文件中的 mappers-package节点,在com.artisan.mybatis.xml.mapper包中增加接口

MultiDBMapper.java

package com.artisan.mybatis.xml.mapper;
public interface MultiDBMapper {
    String getSysTime();
}

编写映射文件


MultiDBMapper.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接口和XML文件关联的时候, namespace的值就需要配置成接口的全限定名称 -->                    
<mapper namespace="com.artisan.mybatis.xml.mapper.MultiDBMapper">
    <select id="getSysTime"  resultType="String" databaseId="mysql">
        select now() from dual
    </select>
     <select id="getSysTime"   resultType="String" databaseId="oracle">
         select  'oralce-'||to_char(sysdate,'yyyy-mm-dd hh24:mi:ss')  from dual 
     </select>
</mapper>   


单元测试

package com.artisan.mybatis.xml.mapper;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.util.Properties;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class MultiDBMapperTest extends BaseMapperTest {
    public String getDatabaseProductName() {
        String productName = null;
        try {
            String dbfile = "db.properties";
            InputStream in = ClassLoader.getSystemResourceAsStream(dbfile);
            Properties p = new Properties();
            p.load(in);
            Class.forName(p.getProperty("jdbc.driver"));
            String url = p.getProperty("jdbc.url");
            String user = p.getProperty("jdbc.username");
            String pass = p.getProperty("jdbc.password");
            Connection con = DriverManager.getConnection(url, user, pass);
            DatabaseMetaData dbmd = con.getMetaData();
            productName = dbmd.getDatabaseProductName();
            System.out.println("数据库名称是:" + productName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return productName;
    }
    @Test
    public void getSysTimeTest() {
        // 获取数据库名称
        getDatabaseProductName();
        // 获取SqlSession
        SqlSession sqlSession = getSqlSession();
        // 获取MultiDBMapper
        MultiDBMapper multiDBMapper = sqlSession.getMapper(MultiDBMapper.class);
        // 调用接口方法
        String sysTime = multiDBMapper.getSysTime();
        System.out.println("当前时间:" + sysTime);
        sqlSession.close();
    }
}


日志

2018-04-27 16:05:57,730  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
2018-04-27 16:05:57,730  INFO [main] (BaseMapperTest.java:29) - reader close successfully
数据库名称是:MySQL
2018-04-27 16:05:57,819 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: select now() from dual 
2018-04-27 16:05:57,929 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 
2018-04-27 16:05:57,959 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: now()
2018-04-27 16:05:57,959 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 2018-04-27 16:05:57.0
2018-04-27 16:05:57,969 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 1
当前时间:2018-04-27 16:05:57.0


当基于不同的数据库运行时,MyBatis会根据配置找到合适的SQL去执行。


注意事项

我们在上面演示了基于databaseId的基本用法,实际在工作中,大部分的SQL还是相同的,没有必要写成2个。这样会导致大量重复的SQL。


数据库的更换可能只会引起某个SQL语句的部分不同, 可以使用if标签配合默认的上下文中的_databaseId参数去实现。

我们用前几篇博文的例子来演示下

改造前

<select id="selectSysUsersAdvancedWithWhere" resultType="com.artisan.mybatis.xml.domain.SysUser">
        SELECT
            a.id,
            a.user_name userName,
            a.user_password userPassword,
            a.user_email userEmail,
            a.user_info userInfo,
            a.head_img headImg,
            a.create_time createTime
        FROM
            sys_user a
        <where>
            <if test="userName != null and userName != '' ">
                and user_name like concat('%',#{userName},'%')
            </if>
            <if test="userEmail != null and userEmail != '' ">
                and user_email = #{userEmail}
            </if>
        </where>
    </select>


改造后

<!-- 多数据库的支持 BEGIN -->
    <select id="selectSysUsersAdvancedMulitDB" resultType="com.artisan.mybatis.xml.domain.SysUser">
        SELECT
            a.id,
            a.user_name userName,
            a.user_password userPassword,
            a.user_email userEmail,
            a.user_info userInfo,
            a.head_img headImg,
            a.create_time createTime
        FROM
            sys_user a
        <where>
            <if test="userName != null and userName != '' ">
                <if test="_databaseId == 'mysql' ">
                    and user_name like concat('%',#{userName},'%')
                </if>
                <if test="_databaseId == 'oracle' ">
                    and user_name like '%'||#{username}||'%'
                </if>
            </if>
            <if test="userEmail != null and userEmail != '' ">
                and user_email = #{userEmail}
            </if>
        </where>
    </select>
    <!-- 多数据库的支持 END -->


增加个接口方法,方便区分测试

/**
     * 
     * 
     * @Title: selectSysUsersAdvancedMulitDB
     * 
     * @Description: selectSysUsersAdvancedMulitDB
     * 
     * @param sysUser
     * @return
     * 
     * @return: List<SysUser>
     */
    List<SysUser> selectSysUsersAdvancedMulitDB(SysUser sysUser);


单元测试

@Test
    public void selectSysUsersAdvancedMulitDBTest() {
        logger.info("selectSysUsersAdvancedMulitDBTest");
        // 获取SqlSession
        SqlSession sqlSession = getSqlSession();
        List<SysUser> userList = null;
        try {
            // 获取UserMapper接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            logger.info("===========1.当用户只输入用户名时,需要根据用户名模糊查询===========");
            // 模拟前台传参 1.当用户只输入用户名时,需要根据用户名模糊查询
            SysUser sysUser = new SysUser();
            sysUser.setUserName("ad");
            // 调用selectSysUserByAdvancedCondition,根据查询条件查询用户
            userList = userMapper.selectSysUsersAdvancedMulitDB(sysUser);
            // 根据数据库sys_user表中的记录,可以匹配到admin, 期望userList不为空
            Assert.assertNotNull(userList);
            // 根据查询条件,期望只有1条数据
            Assert.assertTrue(userList.size() == 1);
            logger.info("userList:" + userList);
            // 为了测试 匹配多条记录的情况,我们将id=1001这条数据的userName 由test 改为artisan
            sysUser.setUserName("i");
            // 调用selectSysUserByAdvancedCondition,根据查询条件查询用户
            userList = userMapper.selectSysUsersAdvancedMulitDB(sysUser);
            // 根据数据库sys_user表中的记录,可以匹配到admin和artisan, 期望userList不为空
            Assert.assertNotNull(userList);
            // 根据查询条件,期望只有2条数据
            Assert.assertTrue(userList.size() == 2);
            logger.info("userList:" + userList);
            logger.info("===========2.当用户只输入邮箱使,根据邮箱进行完全匹配===========");
            // 模拟前台传参 2.当用户只输入邮箱使,根据邮箱进行完全匹配
            sysUser.setUserEmail("admin@artisan.com");
            userList = userMapper.selectSysUsersAdvanced(sysUser);
            Assert.assertNotNull(userList);
            Assert.assertTrue(userList.size() == 1);
            logger.info(userList);
            sysUser.setUserEmail("1admin@artisan.com");
            userList = userMapper.selectSysUsersAdvancedMulitDB(sysUser);
            Assert.assertTrue(userList.size() == 0);
            logger.info("===========3.当用户同时输入用户名和密码时,用这两个条件查询匹配的用户===========");
            // 模拟组合查询条件,存在记录的情况
            sysUser.setUserName("i");
            sysUser.setUserEmail("admin@artisan.com");
            userList = userMapper.selectSysUsersAdvancedMulitDB(sysUser);
            Assert.assertNotNull(userList);
            Assert.assertEquals("admin@artisan.com", sysUser.getUserEmail());
            Assert.assertTrue(userList.size() == 1);
            logger.info(userList);
            logger.info("===========4.当用户同时输入无法匹配的用户名和密码===========");
            // 模拟组合查询条件,不存在记录的情况
            sysUser.setUserName("x");
            sysUser.setUserEmail("admin@artisan.com");
            userList = userMapper.selectSysUsersAdvancedMulitDB(sysUser);
            Assert.assertTrue(userList.size() == 0);
            logger.info(userList);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
            logger.info("sqlSession close successfully ");
        }
    }


日志

2018-04-27 16:22:51,822  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
2018-04-27 16:22:51,826  INFO [main] (BaseMapperTest.java:29) - reader close successfully
2018-04-27 16:22:51,827  INFO [main] (UserMapperTest.java:934) - selectSysUsersAdvancedMulitDBTest
2018-04-27 16:22:51,857  INFO [main] (UserMapperTest.java:943) - ===========1.当用户只输入用户名时,需要根据用户名模糊查询===========
2018-04-27 16:22:51,987 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') 
2018-04-27 16:22:52,086 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: ad(String)
2018-04-27 16:22:52,157 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime
2018-04-27 16:22:52,157 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
2018-04-27 16:22:52,167 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 1
2018-04-27 16:22:52,167  INFO [main] (UserMapperTest.java:953) - userList:[SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理员用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]]
2018-04-27 16:22:52,177 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') 
2018-04-27 16:22:52,177 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String)
2018-04-27 16:22:52,177 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime
2018-04-27 16:22:52,177 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
2018-04-27 16:22:52,177 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
2018-04-27 16:22:52,177 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 2
2018-04-27 16:22:52,187  INFO [main] (UserMapperTest.java:964) - userList:[SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理员用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018], SysUser [id=1001, userName=artisan, userPassword=123456, userEmail=test@artisan.com, userInfo=测试用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]]
2018-04-27 16:22:52,187  INFO [main] (UserMapperTest.java:966) - ===========2.当用户只输入邮箱使,根据邮箱进行完全匹配===========
2018-04-27 16:22:52,187 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE 1=1 and user_name like concat('%',?,'%') and user_email = ? 
2018-04-27 16:22:52,187 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String), admin@artisan.com(String)
2018-04-27 16:22:52,187 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime
2018-04-27 16:22:52,187 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
2018-04-27 16:22:52,187 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 1
2018-04-27 16:22:52,187  INFO [main] (UserMapperTest.java:972) - [SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理员用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]]
2018-04-27 16:22:52,187 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') and user_email = ? 
2018-04-27 16:22:52,197 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String), 1admin@artisan.com(String)
2018-04-27 16:22:52,197 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 0
2018-04-27 16:22:52,197  INFO [main] (UserMapperTest.java:978) - ===========3.当用户同时输入用户名和密码时,用这两个条件查询匹配的用户===========
2018-04-27 16:22:52,197 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') and user_email = ? 
2018-04-27 16:22:52,197 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String), admin@artisan.com(String)
2018-04-27 16:22:52,197 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime
2018-04-27 16:22:52,207 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
2018-04-27 16:22:52,207 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 1
2018-04-27 16:22:52,207  INFO [main] (UserMapperTest.java:987) - [SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理员用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]]
2018-04-27 16:22:52,207  INFO [main] (UserMapperTest.java:989) - ===========4.当用户同时输入无法匹配的用户名和密码===========
2018-04-27 16:22:52,207 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') and user_email = ? 
2018-04-27 16:22:52,207 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: x(String), admin@artisan.com(String)
2018-04-27 16:22:52,207 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 0
2018-04-27 16:22:52,207  INFO [main] (UserMapperTest.java:995) - []
2018-04-27 16:22:52,217  INFO [main] (UserMapperTest.java:1001) - sqlSession close successfully 


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
14天前
|
SQL 数据库
数据库数据恢复—SQL Server数据库报错“错误823”的数据恢复案例
SQL Server附加数据库出现错误823,附加数据库失败。数据库没有备份,无法通过备份恢复数据库。 SQL Server数据库出现823错误的可能原因有:数据库物理页面损坏、数据库物理页面校验值损坏导致无法识别该页面、断电或者文件系统问题导致页面丢失。
79 12
数据库数据恢复—SQL Server数据库报错“错误823”的数据恢复案例
|
7天前
|
SQL XML Java
mybatis复习03,动态SQL,if,choose,where,set,trim标签及foreach标签的用法
文章介绍了MyBatis中动态SQL的用法,包括if、choose、where、set和trim标签,以及foreach标签的详细使用。通过实际代码示例,展示了如何根据条件动态构建查询、更新和批量插入操作的SQL语句。
mybatis复习03,动态SQL,if,choose,where,set,trim标签及foreach标签的用法
|
22小时前
|
SQL 存储 移动开发
HTML5 Web SQL 数据库详解
Web SQL 数据库是 HTML5 中的一种本地存储技术,允许在浏览器中使用 SQL 语言操作本地数据,支持离线访问和事务处理,适用于缓存数据和小型应用。然而,其存储容量有限且仅部分现代浏览器支持,标准已不再积极维护,未来可能被 IndexedDB 和 localStorage 等技术取代。使用时需谨慎考虑兼容性和发展前景。
|
23天前
|
SQL 存储 数据管理
SQL Server数据库
SQL Server数据库
40 11
|
18天前
|
SQL 监控 关系型数据库
MySQL数据库中如何检查一条SQL语句是否被回滚
检查MySQL中的SQL语句是否被回滚需要综合使用日志分析、事务状态监控和事务控制语句。理解和应用这些工具和命令,可以有效地管理和验证数据库事务的执行情况,确保数据的一致性和系统的稳定性。此外,熟悉事务的ACID属性和正确设置事务隔离级别对于预防数据问题和解决事务冲突同样重要。
30 2
|
1月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
30 1
|
1月前
|
SQL 安全 数据库
基于SQL Server事务日志的数据库恢复技术及实战代码详解
基于事务日志的数据库恢复技术是SQL Server中一个非常强大的功能,它能够帮助数据库管理员在数据丢失或损坏的情况下,有效地恢复数据。通过定期备份数据库和事务日志,并在需要时按照正确的步骤恢复,可以最大限度地减少数据丢失的风险。需要注意的是,恢复数据是一个需要谨慎操作的过程,建议在执行恢复操作之前,详细了解相关的操作步骤和注意事项,以确保数据的安全和完整。
59 0
|
2月前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
58 0
|
2月前
|
SQL 数据处理 数据库
|
2月前
|
SQL 存储 调度
下一篇
无影云桌面