SpringBoot入门之三 整合Mybatis及多数据源

1. springboot整合使用jdbcTemplate

1.1 pom文件引入

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
		    <groupId>mysql</groupId>
		    <artifactId>mysql-connector-java</artifactId>
		</dependency>

	</dependencies>

1.2 yml

server :
  port : 8081
spring: 
  datasource: 
    url: jdbc:mysql://localhost:3307/springboot?useUnicode=true&characterEncoding=utf8
###springboot2 多数据源有个bug  url-》jdbc-url
    username: root
    password: 
    driver-class-name: com.mysql.jdbc.Driver

1.3 Mapper代码

2. springboot整合使用mybatis

Mybatis是一款支持复杂的SQL语句,存储过程及高级映射的持久层的框架。使用Mybatis有两种方式,XML和注解。

2.1 SpringBoot+Mybatis注解版

Mybatis初期使用比较麻烦,需要很多配置文件、实体类、dao层映射、还有很多其他的配置。初期开发使用generator可以根据表结构自动生产实体类、dao层代码,这样是可以减轻一部分开发量;后期mybatis进行大量的优化,现在可以使用注解版本,自动管理dao层和配置文件。

mybatis-spring-boot-starte就是SpringBoot集成Mybatis的jar包,可以完全使用注解,无需配置文件,简单配置轻松上手。
2.1.1 在Maven pom.xml文件中加入Mybatis和MySQL的jar包

		<!-- 整合mybatise需要的依赖 -->
		<dependency>
		    <groupId>org.mybatis.spring.boot</groupId>
		    <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
		<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
		</dependency>

2.1.2 配置application.yml文件

spring: 
  datasource: 
    url: jdbc:mysql://localhost:3307/springboot?useUnicode=true&characterEncoding=utf8
###springboot2 多数据源有个bug  url-》jdbc-url
    username: root
    password: 
    driver-class-name: com.mysql.jdbc.Driver
    type : com.alibaba.druid.pool.DruidDataSource

springboot会自动加载spring.datasource.*相关配置,数据源就会自动注入到sqlSessionFactory中,sqlSessionFactory会自动注入到Mapper中。
mybatis-spring-boot-starter的2.0.0与2.1.1版本还是有区别,如果升级到2.1.1,同样的代码会报以下错误
Property ‘sqlSessionFactory’ or ‘sqlSessionTemplate’ are required
为解决多数据源问题,mybatis取消啦自动注入sqlSessionFactory等,可以手动注入,此处不详细展开。

在启动类中添加对mapper包扫描@MapperScan或者在每个Mapper类中增加上面添加注解@Mapper,推荐在启动类加注解,这样不用在每个Mapper类加注解。

@MapperScan("sample.springboot.teach3.mapper")
@SpringBootApplication
public class SpringbootTeach3Application {

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

}

2.1.3 开发Mapper
所有的sql都在注解上。

@Select 是查询类的注解,所有的查询均使用这个

@Result 修饰返回的结果集,关联实体类属性和数据库字段一一对应,如果实体类属性和数据库属性名保持一致,就不需要这个属性来修饰。

@Insert 插入数据库使用,直接传入实体类会自动解析属性到对应的值

@Update 负责修改,也可以直接传入对象

@delete 负责删除

更多方法请参考mybatis官方地址

http://www.mybatis.org/mybatis-3/zh/java-api.html

2.1.4 使用
启动项目成功在浏览器输入本机的地址。
在这里插入图片描述

源码中controler层有完整的增删改查,这里就不贴了。

常见问题

注意#和$的问题?

#方式能够很大程度防止sql注入,#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的值是id,则解析成的sql为order by “id”

方 式 无 法 防 止 S q l 注 入 , 方式无法防止Sql注入, Sql将传入的数据直接显示生成在sql中。如:order by u s e r i d user_id userid,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id。$方式一般用于传入数据库对象,例如传入表名。

使用MyBatis排序时使用order by 动态参数时需要注意,用$而不是#。

#{} 这种取值是编译好SQL语句再取值

${} 这种是取值以后再去编译SQL语句

2.2 SpringBoot+Mybatis XML版本

xml版本保持映射文件的老传统,优化主要体现在不需要实现dao的是实现层,而是在映射的xml文件中找到相应的sql语句。
2.2.1 配置文件application.yml文件中增加配置

#mybatis
mybatis:
  mapper-locations: classpath:sample.springboot.teach3.mapper/*.xml
  type-aliases-package: sample.springboot.teach3.model

2.2.2 Mapper XML本人使用mybatis generator生成器,具体配置生成器的方法不在此展开。代码如下

在这里插入图片描述

2.2.3Dao层
Dao层也是自动生成,可增加自定义接口

public interface UserMapper {

    User findMyName(@Param("name") String name);

    @Insert("INSERT INTO USERS(USER_NAME,AGE) VALUES(#{name},#{age})")
    int add(@Param("name") String naem, @Param("age") Integer age);

    int deleteByPrimaryKey(Integer id);

    int insert(User record);

    int insertSelective(User record);

    User selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(User record);

    int updateByPrimaryKey(User record);
}

2.2.4
启动,遇到错误如下

 Cause: java.lang.IllegalArgumentException: Result Maps collection already contains value for xyx.dsw.dao.mapper.admin.quotationwish.TempTestTableMapper.TempTestTableResult 

原因分析:

由于使用ibatis的TempTestTableMapper.xml实现接口TempTestTableMapper.java中的方法的时候的id有重复的值,查看XXXMapper.xml,发现执行多次mybatis generator 所致.

查询功能,在url页面的测试。
在这里插入图片描述
源码中controler层有完整的增删改查,这里就不贴了
注解和xml如何选择呢?
注解版适合简单快速的模式。
xml版比较适合大型项目,可以灵活的动态生成SQL,方便调整SQL。

3. 集成mybatis generator插件

方法

  1. eclipse下用maven插件+Mabatis-generator生成mybatis的文件,
  2. 安装MybatisGenerator插件 此方式不再此展开

3.1. 配置Maven pom.xml 文件

在pom.xml增加以下插件:

<plugin>
				<groupId>org.mybatis.generator</groupId>
				<artifactId>mybatis-generator-maven-plugin</artifactId>
				<version>1.3.2</version><!--jar包去生成对应类 需要连接数据库 数据连接的版本和项目中的一致 -->
				<dependencies>
					<dependency>
						<groupId>mysql</groupId>
						<artifactId>mysql-connector-java</artifactId>
						<version>5.1.45</version>
					</dependency>
				</dependencies>
				<configuration><!--MBG配置文件的路径 -->
					<configurationFile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>
					<overwrite>true</overwrite>
				</configuration>
			</plugin>

配置好Maven插件,下面需要配置插件需要mybatis-generator的配置文件

3.2. 配置mybatis-generator的配置文件

添加配置文件到resource下:

generatorConfig.xml的内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
 <generatorConfiguration>
	<context id = "test " targetRuntime="MyBatis3">
		<plugin type ="org.mybatis.generator.plugins.EqualsHashCodePlugin">
		</plugin>
		<plugin type ="org.mybatis.generator.plugins.SerializablePlugin">
		</plugin>
		<plugin type ="org.mybatis.generator.plugins.ToStringPlugin">
		</plugin>
		<commentGenerator><!-- 这个元素用来去除指定生成的注释中是否包含生成的日期 false:表示包含 --><!-- 如果生成日期,会造成即使修改一个字段,整个实体类所有属性都会发生变化,不利于版本控制,所以设置为true -->
			<property name = "suppressDate" value="true" /><!-- 是否去除自动生成的注释 			true:是 : false:否 -->
			<property name = "suppressAllComments" value="true" />
		</commentGenerator><!--数据库链接URL,用户名、密码 -->
		<jdbcConnection driverClass ="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3307/springboot"		userId="root" password="">
		</jdbcConnection>
		<javaTypeResolver>
			<property name = "forceBigDecimals" value="false" />
		</javaTypeResolver>
		<!-- 生成实体类的包名和位置 -->
		<javaModelGenerator targetPackage ="sample.springboot.teach3.model" targetProject="src/main/java">
			<property name = "enableSubPackages" value="true" />
			<property name = "trimStrings" value="true" />
		</javaModelGenerator>
		<!--生成映射文件的包名和位置 com/lu/mapper -->
			<sqlMapGenerator targetPackage ="sample.springboot.teach3.mapper" targetProject="src/main/resources">
				<property name = "enableSubPackages" value="true" />
			</sqlMapGenerator><!-- 生成DAO的包名和位置 mybatis两种开发模式 xml 注解式 -->
			<!-- <javaClientGenerator type = "XMLMAPPER"	targetPackage="sample.springboot.teach3.mapper" targetProject="src/main/java">
				<property name = "enableSubPackages" value="true" />
			</javaClientGenerator> -->
			<!-- 要生成哪些表 -->
			<table tableName = "users" domainObjectName="User"		enableCountByExample="false" enableUpdateByExample="false"
				enableDeleteByExample="false" enableSelectByExample="false"
				selectByExampleQueryId="false">
			</table>
		</context>
</generatorConfiguration>

3.3 生成代码

在eclipse 中,选择pom.xml文件,击右键先择Run AS——>Maven Build… ——>在Goals框中输入:mybatis-generator:generate,
在这里插入图片描述
maven会先下载插件,然后生成代码。

看效果:

在这里插入图片描述

4. 配置多数据源

SpringBoot多数据源也就是在一个jar存在多个不同的jdbc数据库连接。
在一个项目中存在会员、订单、支付模块,只分包,并不算分布式项目。
分布式项目是将一个大的项目拆分多个不同子项目,子项目之间采用rpc远程调用通信技术。假设我们的数据库分为会员数据库、订单数据库、支付数据库等,存在不同的jdbc;多数据库如何定位自己的数据源:

  1. 分包名
    sample.teach2.user-- 数据用就是会员,或用户
    sample.teach2.order-订单数据库
  2. 注解形式
    在service层引入@DataSource(“XXX”) ,不常用。本文仅使用第一种

4.1.首先定义数据源配置

#=====================multiple database config============================
spring: 
  datasource: 
    user:
      jdbc-url: jdbc:mysql://localhost:3307/springboot?useUnicode=true&characterEncoding=utf8
  ###springboot2 多数据源有个bug  url-》jdbc-url
      username: root
      password: 
      driver-class-name: com.mysql.jdbc.Driver
    order :
      jdbc-url: jdbc:mysql://localhost:3307/springboot2?useUnicode=true&characterEncoding=utf8
  ###springboot2 多数据源有个bug  url-》jdbc-url
      username: root
      password: 
      driver-class-name: com.mysql.jdbc.Driver
###    type : com.alibaba.druid.pool.DruidDataSource

4.2. 配置数据源的相关注入数据源对象

第一个数据源配置

@Configuration
@MapperScan(basePackages = "sample.springboot.teach3.user", sqlSessionTemplateRef = "userSqlSessionTemplate")
public class UserDataSourceConfig {

    @Bean("userDataSource")
    @ConfigurationProperties("spring.datasource.user")
    public DataSource userDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "userSqlSessionFactory")
    public SqlSessionFactory userSqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(userDataSource());
        return sqlSessionFactoryBean.getObject();
    }

    @Bean(name = "userTransactionManager")
    public DataSourceTransactionManager userTrancationManager(@Qualifier("userDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "userSqlSessionTemplate")
    public SqlSessionTemplate
        userSqlSessionTemplate(@Qualifier("userSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

相关知识点:
1.使用@Bean可以创建一个bean对象交给spring容器管理
2.@Bean创建的bean对象的名称默认为方法名,也可以指定
3.@Bean方法参数表示,接收一个bean对象,默认按照type类型接收注入的对象,若要修改为byName方式,可以使用@Qualifier注解注入准确的对象
4.@Primary表示该bean为此类型的默认bean,在其他地方引用的时候用@Autowired即可按照类型注入,不受同类型多个对象影响

其他注解就不清楚了!

2.配置第二个数据源

@Configuration
@MapperScan(basePackages = "sample.springboot.teach3.order", sqlSessionTemplateRef = "orderSqlSessionTemplate")
public class OrderDataSourceConfig {

    @Bean("orderDataSource")
    @ConfigurationProperties("spring.datasource.order")
    public DataSource orderDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "orderSqlSessionFactory")
    public SqlSessionFactory orderSqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(orderDataSource());
        return sqlSessionFactoryBean.getObject();
    }

    @Bean(name = "orderTransactionManager")
    public DataSourceTransactionManager orderTrancationManager(@Qualifier("orderDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "orderSqlSessionTemplate")
    public SqlSessionTemplate
        orderSqlSessionTemplate(@Qualifier("orderSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

4.3. Dao数据持久层

public interface UserMapper {

    User findMyName(@Param("name") String name);

    @Insert("INSERT INTO USERS(USER_NAME,AGE) VALUES(#{name},#{age})")
    int add(@Param("name") String name, @Param("age") Integer age);

    int deleteByPrimaryKey(Integer id);

    int insert(User record);

    int insertSelective(User record);

    User selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(User record);

    int updateByPrimaryKey(User record);
}
public interface OrderMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Order record);

    int insertSelective(Order record);

    Order selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Order record);

    int updateByPrimaryKey(Order record);
}

上面两个接口分属两个数据源,

4.4 Service服务层,注意事务

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    public boolean addOrder(Integer userId, Integer total) {
        Order order = new Order();
        order.setTotal(Float.valueOf(total));
        order.setUserId(userId);
        int result = orderMapper.insertSelective(order);
        return result > 0 ? true : false;
    }
}
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public boolean addUser2(String userName, Integer age) {
        int result = userMapper.add(userName, age);
        return result > 0 ? true : false;
    }

    public User getById(Integer id) {
        return userMapper.selectByPrimaryKey(id);
    }
}

4.5 知识扩展

1.如果采用传统jpa方式,@EnableJpaRepositories无需配置,配置了也无影响。实现方式如下:

ds1相关DaoImpl

@PersistenceContext
private EntityManager entityManager;

ds2相关DaoImpl

@PersistenceContext(unitName = “secondDs”)
private EntityManager entityManager;

因为ds1的entityManger声明了@Primary,所以无需指明unitName,ds2必须指明。注入了准确的entityManager,就可以直接拿来操作数据库了。service层和上面一样的,@Transactional(“xxxManager”)指明事物管理器即可!

2.采用jdbcTemplate方式,直接注入到Service层对象即可,so easy!

@Autowired
private JdbcTemplate jdbcTemplate;

@Autowired
private TransactionTemplate transactionTemplate;

@Resource(name=“jdbcTemplate2”)
private JdbcTemplate jdbcTemplate2;

@Resource(name=“transactionTemplate2”)
private TransactionTemplate transactionTemplate2;

好了,spring boot 多数据源,完美解决! 而且三种数据库操作方法均支持,包括事物。已经经过实践证明了! 这是官方给出的最佳实践,只是官方文档没写细而已。

源码地址

https://gitee.com/xiaolaifeng/sample.springboot/tree/master/springboot-teach3
注解版:
XML版:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮华落定

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值