2024-09-04

MyBatis-Plus 是一个对 MyBatis 的增强工具,在 MyBatis 的基础上只做增强,不做改变,为简化开发、提高效率而生。

要从 MyBatis 迁移到 MyBatis-Plus,你需要做以下几个步骤:

  1. 引入 MyBatis-Plus 依赖
  2. 配置 MyBatis-Plus 的 SQL 会话工厂或者数据源
  3. 替换 MyBatis 的 Mapper 接口为 MyBatis-Plus 的 Mapper 接口
  4. 使用 MyBatis-Plus 提供的高级功能,如自动填充、乐观锁等

以下是一个简单的迁移示例:

  1. 修改 pom.xml 添加 MyBatis-Plus 依赖(以 Maven 为例):



<!-- 添加 MyBatis-Plus 依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>最新版本</version>
</dependency>
  1. 配置 application.propertiesapplication.yml,添加数据源和 MyBatis-Plus 配置:



# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/your_database?useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
 
# MyBatis-Plus 配置
mybatis-plus.mapper-locations=classpath:/mapper/*.xml
mybatis-plus.type-aliases-package=com.yourpackage.model
mybatis-plus.global-config.db-config.id-type=auto
mybatis-plus.global-config.db-config.field-strategy=not_empty
mybatis-plus.global-config.db-config.table-prefix=tbl_
  1. 修改 Mapper 接口,继承 MyBatis-Plus 提供的 BaseMapper 接口:



// 旧的 MyBatis Mapper 接口
public interface YourModelMapper {
    // ... 原有的方法定义
}
 
// 新的 MyBatis-Plus Mapper 接口
public interface YourModelMapper extends BaseMapper<YourModel> {
    // MyBatis-Plus 提供的通用 CRUD 方法
}
  1. 使用 MyBatis-Plus 提供的高级功能,如自动填充、乐观锁等,需要在实体类和 Mapper 中相应配置。



// 实体类
@TableName("your_table")
public class YourModel {
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    // ... 其他字段
 
    // 其他业务方法
}
 
// Mapper 接口
public interface YourModelMapper extends BaseMapper<YourModel> {
    // 可以继续添加自定义方法
}

以上步骤只是迁移的基本框架,具体还需要根据项目的实际情况进行调整,比如数据库表的结构、实体类的定义、自定义的 SQL 映射等。

2024-09-04

Oracle的监听器日志文件(listener.log)可能会变得非常大,并占用大量磁盘空间。要清理监听器日志,可以按如下步骤操作:

  1. 停止监听器:

    
    
    
    lsnrctl stop
  2. 删除监听器日志文件。这个文件通常位于$ORACLE_HOME/network/log目录下,名为listener.log

    
    
    
    rm $ORACLE_HOME/network/log/listener.log
  3. 如果需要,可以创建一个新的监听器日志文件。这样做可以防止监听器在下次启动时因为找不到日志文件而报错。

    
    
    
    lsnrctl start

请注意,在执行这些操作之前确保你有足够的权限,并且知道如何安全地停止监听器服务。如果你不确定,最好咨询数据库管理员或者Oracle专业人员。

2024-09-04

在Vue 3和Element Plus中,你可以使用Sortable.js来实现表格行的拖拽重排序。以下是一个简单的例子:

  1. 安装Sortable.js依赖:



npm install sortablejs
  1. 在Vue组件中使用Sortable.js:



<template>
  <el-table
    :data="tableData"
    row-key="id"
    border
    style="width: 100%">
    <el-table-column
      prop="date"
      label="日期"
      width="180">
    </el-table-column>
    <el-table-column
      prop="name"
      label="姓名"
      width="180">
    </el-table-column>
    <!-- 其他列 -->
  </el-table>
</template>
 
<script>
import { ref, onMounted } from 'vue';
import Sortable from 'sortablejs';
 
export default {
  setup() {
    const tableData = ref([
      { id: 1, date: '2016-05-02', name: 'John' },
      { id: 2, date: '2016-05-04', name: 'Doe' },
      // 更多数据...
    ]);
 
    onMounted(() => {
      const el = document.querySelector('.el-table__body-wrapper tbody');
      const sortable = Sortable.create(el, {
        animation: 150,
        delay: 0,
        onEnd: (evt) => {
          const newIndex = evt.newIndex;
          const oldIndex = evt.oldIndex;
          if (newIndex !== oldIndex) {
            const targetRow = tableData.value.splice(oldIndex, 1)[0];
            tableData.value.splice(newIndex, 0, targetRow);
          }
        }
      });
    });
 
    return {
      tableData
    };
  }
};
</script>

在这个例子中,我们使用了el-tableel-table-column组件来展示表格,并通过row-key属性指定了每行的唯一键。在onMounted钩子中,我们使用document.querySelector选中表格的 tbody 元素,并创建了一个Sortable实例。在onEnd事件中,我们通过evt.newIndexevt.oldIndex得知拖拽后的新位置和旧位置,然后通过Vue的响应式数组方法splice来实现数据的重排序。

2024-09-04



import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.function.ServerResponse;
 
import reactor.core.publisher.Flux;
 
@RestController
public class SseController {
 
    @GetMapping("/stream-sse")
    public Flux<ServerResponse> streamSse() {
        // 使用 ServerResponse 的构建器创建 SSE 响应
        Flux<ServerResponse> responseFlux = Flux.interval(Duration.ofSeconds(1))
            .map(seq -> ServerResponse.ok()
                .contentType(MediaType.TEXT_EVENT_STREAM)
                .body(BodyInserters.fromObject("data: " + seq + "\n\n")));
 
        return responseFlux;
    }
}

这段代码使用了Spring WebFlux框架的Flux来创建一个服务端发送事件(SSE)的响应流。它每隔1秒发送一个事件,并且使用标准的SSE格式,即包含data:行和换行符。这个流可以被客户端作为持续的数据源来接收更新。

2024-09-04

Spring Cloud Alibaba 是一个微服务开发平台,它整合了阿里巴巴的一些开源技术,如 Nacos 作为服务注册和配置中心。在使用 Spring Cloud Alibaba 相关技术时,确定版本兼容性是关键。

Spring Cloud Alibaba 的版本是和 Spring Boot 版本及 Spring Cloud 版本相关联的。你可以在 Spring Cloud Alibaba 的官方文档中找到这些版本的对应关系。

以下是一个版本确定的示例步骤:

  1. 确定你的 Spring Boot 版本。
  2. 查看 Spring Cloud 的最新稳定版本。
  3. 参考 Spring Cloud Alibaba 的官方文档,找到对应的版本关系表。
  4. 选择一个兼容的 Spring Cloud Alibaba 版本。

举例,如果你使用的 Spring Boot 版本是 2.3.1.RELEASE,Spring Cloud 版本是 Hoxton.SR5,那么你可以查看 Spring Cloud Alibaba 的版本关系表找到相应的版本。

在实际操作中,你可以在项目的 pom.xml 文件中指定版本:




<!-- Spring Cloud Alibaba -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
 
<!-- Nacos 客户端 -->
<dependencies>
    <dependency>
        <groupId>com.alibaba.nacos</groupId>
        <artifactId>nacos-client</artifactId>
        <version>1.2.0</version>
    </dependency>
</dependencies>

在这个例子中,我们指定了 Spring Cloud Alibaba 的版本为 2.2.1.RELEASE,同时添加了 Nacos 客户端的依赖。

确保你使用的所有库版本之间相互兼容,这样才能保证你的应用平稳运行。

2024-09-04

Tomcat的组件架构主要包括连接器(Connectors),容器(Containers)和服务(Services)。连接器负责处理网络连接,容器负责管理Servlet的执行环境,服务则将它们组合在一起提供Web服务。

以下是Tomcat的简化组件示意图:




          __________
         |         |
         | Connectors|
         |         |
         |_________|
            /     \
           /       \
      ______      ______
     |      |    |      |
     |      |    |      |
     | Container | Container | ...
     |      |    |      |
     |______|    |______|
            \     /
             \   /
              ______
             |      |
             |      |
             | Service |
             |      |
             |______|

数据流示意图:




Client <-> Connector <-> Container <-> Servlet <-> DB

Client:客户端发送请求到Tomcat服务器。

Connector:负责接收客户端请求,并将请求封装成Request和Response对象。

Container:负责管理和执行Servlet,处理请求和生成响应。

Servlet:实际处理业务逻辑的组件。

DB:数据库,如果需要的话,Servlet处理完业务逻辑后与数据库交互。

代码实例不适合在这里给出,因为这涉及到具体的业务逻辑实现。但是,可以提供一个简单的Servlet示例来说明数据是如何在Tomcat中流动的:




import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
 
public class SimpleServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println("<html><body><h1>Hello World</h1></body></html>");
    }
}

这个简单的Servlet处理GET请求,并响应一个包含“Hello World”的HTML页面。在实际部署到Tomcat后,客户端的请求会通过Connector,被传递给Servlet容器,然后Servlet容器会调用这个Servlet的doGet方法来处理请求,并生成响应返回给客户端。

2024-09-04



import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
 
// 自定义事件
public class MyCustomEvent extends ApplicationEvent {
    public MyCustomEvent(Object source) {
        super(source);
    }
}
 
// 自定义监听器
@Configuration
public class MyCustomListener implements ApplicationListener<MyCustomEvent> {
    @Override
    public void onApplicationEvent(MyCustomEvent event) {
        // 处理事件逻辑
        System.out.println("MyCustomListener received MyCustomEvent: " + event);
    }
}
 
// 触发事件的地方
@Configuration
public class EventPublisher {
    
    private final ApplicationEventPublisher publisher;
 
    public EventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }
 
    public void publish() {
        MyCustomEvent event = new MyCustomEvent(this);
        publisher.publishEvent(event);
    }
}
 
// 在SpringBoot启动完成后发布事件
@Configuration
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
    private final EventPublisher eventPublisher;
 
    public StartupListener(EventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }
 
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getParent() == null) {
            // 发布事件
            eventPublisher.publish();
        }
    }
}

这个代码示例展示了如何在SpringBoot应用中定义、监听和发布自定义事件。MyCustomEvent是一个自定义事件类,MyCustomListener是监听该事件的监听器。EventPublisher类中的publish方法用于发布事件,而StartupListener则在SpringBoot启动完成后发布事件。这个例子有助于理解Spring的事件机制,并在实际应用中进行事件驱动的开发。

2024-09-04

由于Oracle 11g不再支持CentOS 7,安装过程可能会遇到许多问题。以下是安装Oracle 11g的基本步骤,但是不保证每个步骤都能成功执行,因为官方不再提供支持:

  1. 系统要求:

    • 至少2GB物理内存
    • 至少400MB的交换空间
    • 至少3GB可用磁盘空间
  2. 安装必要的依赖包:

    
    
    
    sudo yum install -y binutils compat-libstdc++-33 elfutils-libelf elfutils-libelf-devel gcc gcc-c++ glibc glibc-common glibc-devel glibc-headers ksh libaio libaio-devel libgcc libstdc++ libstdc++-devel libXi libXtst make sysstat
  3. 创建Oracle用户和组:

    
    
    
    sudo groupadd oinstall
    sudo groupadd dba
    sudo useradd -g oinstall -G dba oracle
    sudo passwd oracle
  4. 配置内核参数和用户限制,编辑或添加以下行到 /etc/sysctl.conf/etc/security/limits.conf

    
    
    
    # /etc/sysctl.conf
    fs.file-max = 6815744
    kernel.sem = 250 32000 100 128
    kernel.shmmax = 536870912
    net.ipv4.ip_local_port_range = 1024 65000
    net.core.rmem_default = 262144
    net.core.rmem_max = 4194304
    net.core.wmem_default = 262144
    net.core.wmem_max = 1048576
     
    # /etc/security/limits.conf
    oracle soft nproc 2047
    oracle hard nproc 16384
    oracle soft nofile 1024
    oracle hard nofile 65536
  5. 应用内核参数更改:

    
    
    
    sudo sysctl -p
  6. 创建Oracle安装目录并设置权限:

    
    
    
    sudo mkdir -p /u01/app/oracle
    sudo chown -R oracle:oinstall /u01
    sudo chmod -R 775 /u01
  7. 设置Oracle用户的环境变量,编辑~oracle/.bash_profile

    
    
    
    export ORACLE_BASE=/u01/app/oracle
    export ORACLE_HOME=$ORACLE_BASE/product/11.2.0/db_1
    export ORACLE_SID=ORCL
    export PATH=$PATH:$ORACLE_HOME/bin
  8. 登录到Oracle用户并下载Oracle 11g安装文件。
  9. 解压安装文件并运行安装程序:

    
    
    
    unzip oracle_database_linux32.zip
    cd database/
    ./runInstaller
  10. 安装完成后,运行Oracle的配置助手(CA):

    
    
    
    $ORACLE_HOME/bin/dbca
  11. 最后,配置Oracle的监听器和网络设置:

    
    
    
    $ORACLE_HOME/bin/netca
    $ORACLE_HOME/bin/lsnrctl start

注意:这只是一个基本的安装指南,实际安装可能需要根据系统环境和具体需求做出调整。由于CentOS 7不再支持,Oracle官方没有提供对11g的支持

2024-09-04

在Oracle中,补齐两位小数可以使用TO_CHAR函数结合FM999999990.00格式模型,而要在不足两位小数时前面补零,可以使用LPAD函数。

以下是一个示例,演示如何对数字进行两位小数的补齐,以及在小数点前补零:




SELECT TO_CHAR(your_column, 'FM999999990.00') AS padded_number
FROM your_table;

如果你想要在小于1的数字前面补0,可以使用LPAD函数结合TO_CHAR函数:




SELECT LPAD(TO_CHAR(your_column, 'FM99999990.00'), 12, '0') AS padded_number
FROM your_table;

这里,LPAD函数将TO_CHAR格式化后的结果补到12位长度,不足的部分通过第三个参数'0'进行了前补零。

2024-09-04

这里提供一个简化版本的分布式锁实现,使用Redis和ZooKeeper的简单示例。

Redis分布式锁实现:




import redis.clients.jedis.Jedis;
 
public class RedisDistributedLock {
    private Jedis jedis;
    private String lockKey;
    private int expireTime; // 锁的超时时间
 
    public RedisDistributedLock(Jedis jedis, String lockKey, int expireTime) {
        this.jedis = jedis;
        this.lockKey = lockKey;
        this.expireTime = expireTime;
    }
 
    public boolean lock() {
        String result = jedis.set(lockKey, "locked", "NX", "PX", expireTime);
        return "OK".equals(result);
    }
 
    public boolean unlock() {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList("locked"));
        return result.equals(1L);
    }
}

Zookeeper分布式锁实现:




import org.apache.zookeeper.*;
 
public class ZkDistributedLock implements Watcher {
    private ZooKeeper zk;
    private String lockName;
    private String waitNode;
 
    public ZkDistributedLock(String hostPort, String lockName) throws Exception {
        this.lockName = lockName;
        zk = new ZooKeeper(hostPort, 3000, this);
        waitNode = zk.create("/locks/" + lockName, "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
    }
 
    public void lock() throws KeeperException, InterruptedException {
        while (true) {
            try {
                zk.exists("/locks/" + lockName, true);
                System.out.println("Waiting for lock...");
                synchronized (this) {
                    wait();
                }
                System.out.println("Lock acquired");
                break;
            } catch (KeeperException.NoNodeException e) {
                // Lock acquired
                break;
            }
        }
    }
 
    public void unlock() throws KeeperException, InterruptedException {
        zk.delete(waitNode, -1);
        zk.close();
    }
 
    @Override
    public void process(WatchedEvent event) {
        if (event.getType() == Event.EventType.NodeDeleted) {
            synchronized (this) {
                notifyAll();
            }
        }
    }
}

以上代码提供了使用Redis和Zookeeper实现分布式锁的简单示例。在实际应用中,你需要根据具体需求进行安全性和性能的优化,例如使用参数化的Redis命令防止死锁,或者使用Zookeeper的有序节点来实现锁。