代码改变世界

spring boot mybatis整合 druid多数据源

2023-03-18 21:45  youxin  阅读(391)  评论(0编辑  收藏  举报

地址:https://github.com/CodingDocs/springboot-guide/tree/master

在线阅读:spring boot guide指南

 

引入依赖:

 

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--数据库依赖-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!--mybatis依赖-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.1.1</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

 

 

  • spring-boot-starter-web: 可以为Web开发提供支持,为我们提供了嵌入的 Servlet 容器以及 Spring MVC 的依赖,并为 Spring MVC 提供了大量自动配置。
  • mysql-connector-java:数据库驱动包。
  • mybatis-spring-boot-starter:连接 Spring BootMyBatis,构建基于 Spring BootMyBatis 应用程序。
  • lombok:简化Java代码的工具包。

 
 

添加了“余额money”字段是为了给大家简单的演示一下事务管理的方式。

建表语句:

CREATE TABLE `user` (
  `id` int(13) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(33) DEFAULT NULL COMMENT '姓名',
  `age` int(3) DEFAULT NULL COMMENT '年龄',
  `money` double DEFAULT NULL COMMENT '账户余额',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8

1.5 配置 application.properties

由于我使用的是比较新的Mysql连接驱动,所以配置文件可能和之前有一点不同。

server.port=8333
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/erp?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

注意:我们使用的 mysql-connector-java 8+ ,JDBC 连接到mysql-connector-java 6+以上的需要指定时区 serverTimezone=GMT%2B8。另外我们之前使用配置 Mysql数据连接是一般是这样指定driver-class-name=com.mysql.jdbc.Driver,但是现在不可以必须为 否则控制台下面的异常:

Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

上面异常的意思是:com.mysql.jdbc.Driver 被弃用了。新的驱动类是 com.mysql.cj.jdbc.Driver。驱动程序通过SPI自动注册,手动加载类通常是不必要。

如果你非要写把com.mysql.jdbc.Driver 改为com.mysql.cj.jdbc.Driver 即可。

1.6 创建用户类 Bean

User.java

public class User {
    private int id;
    private String name;
    private int age;
    private double money;
    ...
    此处省略getter、setter以及 toString方法
}

二 全注解的方式

先来看一下 全注解的方式,这种方式和后面提到的 xml 的方式的区别仅仅在于 一个将 sql 语句写在 java 代码中,一个写在 xml 配置文件中。全注方式解转换成 xml 方式仅需做一点点改变即可,我在后面会提到。

2.1 Dao 层开发

UserDao.java

@Mapper
public interface UserDao {
    /**
     * 通过名字查询用户信息
     */
    @Select("SELECT * FROM user WHERE name = #{name}")
    User findUserByName(@Param("name") String name);

    /**
     * 查询所有用户信息
     */
    @Select("SELECT * FROM user")
    List<User> findAllUser();

    /**
     * 插入用户信息
     */
    @Insert("INSERT INTO user(name, age,money) VALUES(#{name}, #{age}, #{money})")
    void insertUser(@Param("name") String name, @Param("age") Integer age, @Param("money") Double money);

    /**
     * 根据 id 更新用户信息
     */
    @Update("UPDATE  user SET name = #{name},age = #{age},money= #{money} WHERE id = #{id}")
    void updateUser(@Param("name") String name, @Param("age") Integer age, @Param("money") Double money,
                    @Param("id") int id);

    /**
     * 根据 id 删除用户信息
     */
    @Delete("DELETE from user WHERE id = #{id}")
    void deleteUser(@Param("id") int id);
}

2.2 service 层

@Service
public class UserService {
    @Autowired
    private UserDao userDao;


    /**
     * 根据名字查找用户
     */
    public User selectUserByName(String name) {
        return userDao.findUserByName(name);
    }

    /**
     * 查找所有用户
     */
    public List<User> selectAllUser() {
        return userDao.findAllUser();
    }

    /**
     * 插入两个用户
     */
    public void insertService() {
        userDao.insertUser("SnailClimb", 22, 3000.0);
        userDao.insertUser("Daisy", 19, 3000.0);
    }

    /**
     * 根据id 删除用户
     */

    public void deleteService(int id) {
        userDao.deleteUser(id);
    }

    /**
     * 模拟事务。由于加上了 @Transactional注解,如果转账中途出了意外 SnailClimb 和 Daisy 的钱都不会改变。
     */
    @Transactional
    public void changemoney() {
        userDao.updateUser("SnailClimb", 22, 2000.0, 3);
        // 模拟转账过程中可能遇到的意外状况
        int temp = 1 / 0;
        userDao.updateUser("Daisy", 19, 4000.0, 4);
    }
}

2.3 Controller 层

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/query")
    public User testQuery() {
        return userService.selectUserByName("Daisy");
    }

    @RequestMapping("/insert")
    public List<User> testInsert() {
        userService.insertService();
        return userService.selectAllUser();
    }


    @RequestMapping("/changemoney")
    public List<User> testchangemoney() {
        userService.changemoney();
        return userService.selectAllUser();
    }

    @RequestMapping("/delete")
    public String testDelete() {
        userService.deleteService(3);
        return "OK";
    }

}
2.4 启动类
//此注解表示SpringBoot启动类
@SpringBootApplication
// 此注解表示动态扫描DAO接口所在包,实际上不加下面这条语句也可以找到
@MapperScan("top.snailclimb.dao")
public class MainApplication {

    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }

}

 

 

报错问题:

Caused by: java.lang.UnsupportedClassVersionError: org/mybatis/spring/boot/autoconfigure/MybatisDependsOnDatabaseInitializationDetector has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0

 

降级版本: 我降级到2.3就可以了

去https://mvnrepository.com/ 搜索版本:

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>

https://blog.csdn.net/wstever/article/details/128492151
 

三 xml 的方式

3.1 Dao 层的改动

我这里只演示一个根据姓名找人的方法。

UserDao.java

@Mapper
public interface UserDao {
    /**
     * 通过名字查询用户信息
     */
    User findUserByName(String name);

}

UserMapper.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="top.snailclimb.dao.UserDao">

    <select id="findUserByName" parameterType="String" resultType="top.snailclimb.bean.User">
        SELECT * FROM user WHERE name = #{name}
    </select>
</mapper>

3.2 配置文件的改动

配置文件中加入下面这句话:

mybatis.mapper-locations=classpath:mapper/*.xml

代码地址:https://github.com/Snailclimb/springboot-guide/tree/master/source-code/basis/springboot-mybatis

 

出现:

Invalid bound statement (not found)出现原因和解决方法

其实出现这个问题实质就是mapper接口和mapper.xml文件没有映射起来。
常见的错误如下:
1.mapper.xml中的namespace和实际的mapper文件不一致
这个问题其实很好解决,瞪大眼睛,仔仔细细看看,到底对不对应不就好了嘛

2.mapper接口中的方法名和mapper.xml中的id标签不一致
这个问题和上个问题解决方法一样,仔细对对嘛,这个再对不出来,面壁思过吧。

3.上两步的问题都没有,但是还是不行,可能原因就是,没有构建进去,打开target看看对应的mapper.xml文件在不在

 


原文链接:https://blog.csdn.net/weixin_44695793/article/details/107752054

 

 

  • 编写在resources文件中创建 mapper/UserMapper.xml文件
    注意
    1.namespace中需要与使用@Mapper的接口对应
    2.UserMapper.xml文件名称必须与使用@Mapper的接口一致
    3.标签中的id必须与@Mapper的接口中的方法名一致,且参数一致
<?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="com.zhg.demo.mybatis.mapper.UserMapper">
    <select id="findAll" resultType="User">
        SELECT * FROM tb_user
    </select>
</mapper>

配置文件

注意
1.mybatis中的mapper-locations是mapper的xml文件位置
2.mybatis中的type-aliases-package是为了配置xml文件中resultType返回值的包位置,如果未配置请使用全包名如下:

<select id="findAll" resultType="com.zhg.demo.mybatis.entity.User">
        SELECT * FROM tb_user
</select>

server:
  port: 8081
spring:
  #数据库连接配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://47.107.105.158:3306/test?characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456

#mybatis的相关配置
mybatis:
  #mapper配置文件
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.zhg.demo.mybatis.entity
  #开启驼峰命名
  configuration:
    map-underscore-to-camel-case: true

 

https://juejin.cn/post/7182832936545157175
 
 
 
 

Druid数据库多数据源

Spring的多数据源支持—AbstractRoutingDataSource,AbstractRoutingDataSource定义了抽象的determineCurrentLookupKey方法,子类实现此方法,来确定要使用的数据源

Druid 实现多数据源支持,核心是Overwrite AbstractRoutingDataSource 的 determineCurrentLookupKey 方法

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
     protected DataSource determineTargetDataSource() {
        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
        Object lookupKey = determineCurrentLookupKey();
        DataSource dataSource = this.resolvedDataSources.get(lookupKey);
        if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
            dataSource = this.resolvedDefaultDataSource;
        }
        if (dataSource == null) {
            throw new IllegalStateException("Cannot determine target DataSource for                  lookup key [" + lookupKey + "]");
        }
        return dataSource;
    }

        // 确定当前要使用的数据源
        protected abstract Object determineCurrentLookupKey();
}

 

https://blog.csdn.net/Mr_ming_a_probie/article/details/127920120
 
定义aop切面实现:

定义aop切面实现

https://blog.csdn.net/Mr_ming_a_probie/article/details/127920120

基于

  1. @MapperScan(basePackages = "com.eastmoney.labelmanager.db.mapper.second", sqlSessionTemplateRef = "secondarySqlSessionTemplate")

https://pro.leanote.com/p/5b62d22ba8dc8f244d1324f5

 
https://www.zhihu.com/question/485039988/answer/2489095949
 
集成Druid动态数据源(注解、aop实践)
https://blog.csdn.net/weixin_44213308/article/details/107379350

启动类配置
关键点:去除 exclude = {DataSourceAutoConfiguration.class} 及扫描 com.demo.mapper目录

@MapperScan("com.demo.mapper")
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication .class, args);
}


原文链接:https://blog.csdn.net/xrq1995/article/details/126231539

SpringBoot 配置 Druid多数据源 通过 注解 + AOP 实现线程多数据源切换 AbstractRoutingDataSource多数据源实现 多类型数据库配置

https://blog.csdn.net/m0_52074262/article/details/122136558

 

 

问题原因

日志提示我们没有配置数据源的url属性,我们使用的是druid数据源,而在上面的图示中,url我们是配置的,因此只有一个原因:druid没有识别配置文件中的jdbcUrl

解决

druid在数据源配置时(包含多个数据源配置),数据库链接地址必须使用“url”,其他的url写法无法加载

总计一下:

数据源单数据源配置url写法多数据源配置url写法
druid url url
hikaricp(springboot默认使用的数据源) jdbcUrl jdbc-url
 
 

 

SpringBoot + Mybatis + Druid 配置多数据源

————————————————

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = "com.mulits.datasource.mapper.tel.**",
sqlSessionTemplateRef = "telSqlSessionTemplate")
public class TelDataConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.tel")
    public DataSource telDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public SqlSessionFactory telSqlSessionFactory(@Qualifier("telDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    @Bean
    public DataSourceTransactionManager telTransactionManager(@Qualifier("telDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public SqlSessionTemplate telSqlSessionTemplate(@Qualifier("telSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

 


原文链接:https://blog.csdn.net/weixin_42902577/article/details/106038904

 

 

java使用mysql java.lang.ClassNotFoundException: “com.mysql.cj.jdbc.Driver“

 

https://stackoverflow.com/questions/30651830/use-jdbc-mysql-connector-in-intellij-idea

It’s easy to configure. First just open the IntelliJ IDE and follow this simple step:

File->Project Structure->Libraries

Then click on the plus(+) sign and select 对应的jar文件即可

 

 

jdbc执行原生sql

配置DataSourceConfig

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

/**
 * @Author goujunqiang
 * @Date 2019/10/15
 **/

@Configuration
public class DataSourceConfig {
    @Bean(name = "baseDataSource")
    @ConfigurationProperties(prefix = "spring.datasource") // application.properteis中对应属性的前缀
    @Primary
    public DataSource dataSourceBase() {
        return new DruidDataSource();
    }

    @Bean(name = "resourceJdbcTemplate")
    public JdbcTemplate inditeJdbcTemplate(@Qualifier("baseDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean(name = "scannerCodeDataSource")
    @ConfigurationProperties(prefix = "spring.datasource-white-bucket")
    public DataSource scannerDataSource() {
        return new DruidDataSource();
    }

    @Bean(name = "scannerJdbcTemplate")
    public JdbcTemplate scannerCodeJdbcTemplate(@Qualifier("scannerCodeDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}
package cn.example.restfulapi.sys.task;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Map;

/**
 * @author Mr.Hao
 * @date 2020-04-29
 */
@Component
public class JdbcTest {

    @Resource(name = "resourceJdbcTemplate")
    JdbcTemplate JdbcTemplate;

    @PostConstruct
    public void start(){
        String sql = "SELECT * FROM `snapshot_info` limit 1;";
        Map<String, Object> stringObjectMap = JdbcTemplate.queryForMap(sql);
        System.out.println("=============查询返回一个map==================");
        System.out.println(stringObjectMap);
/*        System.out.println("=============插入数据==================");
        String insertSql = "INSERT INTO snapshot_info VALUES (NULL, ?, ?);";
        int  x = JdbcTemplate.update(insertSql, 7);*/
        System.out.println("===============删除数据================");
        String DeleteSql = "DELETE FROM snapshot_info WHERE id=?;";
        int i = JdbcTemplate.update(DeleteSql, 9944);
        System.out.println("影响的行数: " + i);
        System.out.println("===============更新数据================");
        String updateSql = "UPDATE snapshot_info SET task_id=?  WHERE id=?;";
        int z = JdbcTemplate.update(updateSql, 11, 9943);
        System.out.println("影响的行数: " + z);
        
    }

}

 

 

public Map<String, Object> queryForMap(String sql)
执行查询语句,将一条记录放到一个Map中。


JdbcTemplate查询-queryForList返回一个List集合

 

public List<Map<String, Object>> queryForList(String sql)
执行查询语句,返回一个List集合,List中存放的是Map类型的数据。


https://zhuanlan.zhihu.com/p/363407178
https://zhuanlan.zhihu.com/p/363407178