06、数据访问(下)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 06、数据访问

3、整合MyBatis操作

https://github.com/mybatis

starter

SpringBoot官方的Starter:spring-boot-starter-*

*第三方的: -spring-boot-starter MyBatis属于第三方…

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

83605ad8ee7229b70e76e1a09b0c7181.png

1、配置模式

之前我们使用Mybatis的方式:

编写全局配置文件—>SqlMapConfig.xml


创建SqlSessionFactory:


获取SqlSession


编写Mapper接口.


现在所有的配置都在MybatisAutoConfiguration中.


SqlSessionFactory在MybatisAutoConfiguration自动配置好了.也自动配置了 SqlSessionTemplate,内部 组合了SqlSession.


AutoConfiguredMapperScannerRegistrar:处理我们的Mapper, 只要我们写的操作MyBatis的接口标注了 @Mapper 就会被自动扫描进来

@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })//这些都是Mybatis中的,当导入Mybatis依赖后才会生效.
@ConditionalOnSingleCandidate(DataSource.class) //使用咱们Druid的
@EnableConfigurationProperties(MybatisProperties.class) //Mybatis配置项绑定类
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {
    @Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {...}
    @Bean
  @ConditionalOnMissingBean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {...}
    public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
        ...
    }
}
  • MyBatis的所有配置项都以mybatis开头,全局配置都以mybatis.configuration.XXX开头.

测试代码:

#########################################Account######################################
@Data
public class Account {
    private Long id;
    private String userId;
    private Integer money;
}
###########################################IndexController###########################
@Slf4j
@Controller
public class IndexController {
    @Autowired
    AccountService accountService;
    @ResponseBody
    @GetMapping("/acct")
    public Account getById(@RequestParam("id") Long id){
        return accountService.getAcctById(id);
    }
}
##############################AccountService####################################
public interface AccountService {
    public Account getAcctById(Long id);
}
@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    AccountMapper accountMapper;
    @Override
    public Account getAcctById(Long id) {
        return accountMapper.getAcct(id);
    }
}

配置文件:

####################################AccountMapper.xml################################
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rg.admin.mapper.AccountMapper">
    <select id="getAcct" resultType="com.rg.admin.bean.Account">
        select * from account where id = #{id}
    </select>
</mapper>
###########################################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>
    <!--<settings>-->
    <!--    <setting name="mapUnderscoreToCamelCase" value="true"/>-->
    <!--</settings>-->
    <!--开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。-->
</configuration>
#################################application.yaml################################
spring:
  datasource:
    url: jdbc:mysql:///test
    username: root
    password: 186259
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
#  config-location: classpath:mybatis/mybatis-config.xml #全局配置文件位置
  mapper-locations: classpath:mybatis/mapper/*.xml  #sql映射文件位置
  configuration:
    map-underscore-to-camel-case: true # 开启驼峰命名自动映射(在数据库中映射为_)
# 可以不写全局配置文件;所有全局配置文件的配置都放在configuration配置项中即可

注:配置mybatis.configuration下面的所有,就是相当于改mybatis全局配置文件中的值


SpringBoot整合MyBatis开发步骤总结:


导入mybatis官方starter


编写mapper接口。标准@Mapper注解


编写sql映射文件并绑定mapper接口


在application.yaml中指定Mapper配置文件的位置,以及指定全局配置文件的信息 (建议;配置在mybatis.configuration)

2、注解模式 及混合模式

@Mapper
public interface CityMapper {
    @Select("select * from city where id = #{id}")
    public City getById(Long id);
    // @Insert("insert into  city(`name`,`state`,`country`) values(#{name},#{state},#{country})")
    // @Options(useGeneratedKeys = true,keyProperty = "id")
     // MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键并封装到city中
    public void saveCity(City city);
}
<?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.atguigu.admin.mapper.CityMapper">
    public void insert(City city);
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        insert into  city(`name`,`state`,`country`) values(#{name},#{state},#{country})
    </insert>
</mapper>

最佳实战:


引入mybatis-starter


配置application.yaml中,指定mapper-location位置即可


编写Mapper接口并标注@Mapper注解


简单方法直接注解方式


复杂方法编写mapper.xml进行绑定映射


*@MapperScan(“com.atguigu.admin.mapper”) *简化,其他的接口就可以不用标注@Mapper注解


4、整合 MyBatis-Plus 完成CRUD

1、什么是MyBatis-Plus


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

mybatis plus 官网

建议安装 MybatisX 插件


2、整合MyBatis-Plus

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
里面包含着MybatisPlusAutoConfiguration ,Mybatis核心包,jdbc操作数据库的包,mybatis-spring整合包.

自动配置


MybatisPlusAutoConfiguration 配置类,与MybatisPlusProperties 配置项绑定。mybatis-plus:xxx 就是对mybatis-plus的定制


SqlSessionFactory 自动配置好。底层是容器中默认的数据源


mapperLocations 自动配置好的。有默认值–>classpath*:/mapper/**/*.xml;任意包的类路径下的所有mapper文件夹下任意路径下的所有xml都是sql映射文件。 建议以后sql映射文件,放在 mapper下


容器中也自动配置好了 SqlSessionTemplate


@Mapper 标注的接口也会被自动扫描;建议直接 @MapperScan(“com.atguigu.admin.mapper”) 批量扫描就行


优点:


只需要我们的Mapper继承 BaseMapper 就可以拥有crud能力


3、CRUD功能测试

#########################################UserMapper###############################
//UserMapper
public interface UserMapper extends BaseMapper<User> {
} 
####################################UserService#######################################
public interface UserService extends IService<User> {//T:定义要操作的数据表的实体.
}
@Service
//ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> M要操作的Mapper类,T:对应的实体.
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService  {
}
###############################controller#############################################
//表格数据显示
    @GetMapping("/dynamic_table")
    public String dynamic_table(@RequestParam(value = "pn",defaultValue = "1") Integer pn, Model model){
        //分页查询数据
        Page <User> userPage = new Page <>(pn, 2);
        Page <User> page = userService.page(userPage, null);//分页查询结果.
        //long pages = page.getPages();
       // long current = page.getCurrent();
       // List <User> records = page.getRecords();
        model.addAttribute("page", page);
        return "table/dynamic_table";
    }
//删除用户逻辑
@GetMapping("/user/delete/{id}")
    public String deleteUser(@PathVariable("id") Long id, @RequestParam(value = "pn",defaultValue = "1") Integer pn,
                             RedirectAttributes ra){//RedirectAttributes 重定向携带的数据.
        userService.removeById(id);
        ra.addAttribute("pn", pn);// 会拼在转发路径后面..
        return "redirect:/dynamic_table";
    }
//

静态页面dynamic_table.html

 <div class="panel-body">
                            <div class="adv-table">
                                <table class="display table table-bordered" id="hidden-table-info">
                                    <thead>
                                    <tr>
                                        <th>#</th>
                                        <th>id</th>
                                        <th>name</th>
                                        <th>age</th>
                                        <th>email</th>
                                        <th>操作</th>
                                    </tr>
                                    </thead>
                                    <tbody>
                                        <!--  表格数据显示  -->
                                    <tr class="gradeX" th:each="user,status:${page.records}">
                                        <td th:text="${status.count}">Trident</td>
                                        <td th:text="${user.id}"></td>
                                        <td th:text="${user.name}">Win 95+</td>
                                        <td th:text="${user.age}">4</td>
                                        <td>[[${user.email}]]</td>
                                        <td>
                                            <!--   点击删除当前记录,并返回本页. -->
                                            <a th:href="@{/user/delete/{id}(id=${user.id},pn=${page.current})}" class="btn btn-danger btn-sm" type="button">删除</a>
                                        </td>
                                    </tr>
                                    </tbody>
                                </table>
                               <!--  分页代码  -->
                                <div class="row-fluid">
                                    <div class="span6">
                                        <div class="dataTables_info" id="hidden-table-info_info">当前 第 [[${page.current}]] 页 总计 [[${page.pages}]] 页
                                            共 [[${page.total}]]
                                            记录
                                        </div>
                                    </div>
                                    <div class="span6">
                                        <div class="dataTables_paginate paging_bootstrap pagination">
                                            <ul>
                                                <li class="prev disabled"><a href="#">← Previous</a></li>
                                                <!--  单击之后跳转到指定页  -->
                                                <li th:class="${num == page.current ? 'active' :'' }" th:each="num:${#numbers.sequence(1,page.pages)}">
                                                    <a th:href="@{/dynamic_table(pn=${num})}" >[[${num}]]</a>
                                                </li>
                                                <li class="next"><a href="#">Next → </a></li>
                                            </ul>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>

效果展示:

ef3ca89bd79843f2b04fc531803a0a27.png

2、NoSQL

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

1、Redis自动配置

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

c2d4abc8fa6d68d00678d52c039a679b.png

自动配置:


RedisAutoConfiguration 自动配置类。RedisProperties 属性类 --> spring.redis.xxx是对redis的配置


连接工厂是准备好的。LettuceConnectionConfiguration、JedisConnectionConfiguration


自动注入了RedisTemplate<Object, Object> : xxxTemplate都是工具类;


自动注入了StringRedisTemplate;k:v都是String


底层只要我们使用 StringRedisTemplate、RedisTemplate就可以操作redis


redis环境搭建


1、阿里云按量付费redis。经典网络


2、申请redis的公网连接地址


3、修改白名单 允许0.0.0.0/0 访问


有个默认账号,当然也可以申请多个账号.


使用完后要记得释放下…


2、RedisTemplate与Lettuce


    @Test
    void testRedis(){
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        operations.set("hello","world");
        String hello = operations.get("hello");
        System.out.println(hello);
    }

3、切换至jedis

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
<!--        导入jedis客户端操作redis(因为默认还有Lettuce也可以进行操作.)-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
spring:
  redis:
#    redis://user:password@example.com:6379
    url: redis://lxy:Lxy123456@r-bp1r5uws0tty3chbv7pd.redis.rds.aliyuncs.com:6379
    jedis:
      pool:
        max-active: 10 # 最大活跃数

案例:显示main.html以及sql的访问次数到main页面.

#################################Interceptor########################################
@Component
public class RedisUrlCountInterceptor implements HandlerInterceptor {
    @Autowired
    StringRedisTemplate redisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String uri = request.getRequestURI();
        //默认每次访问当前uri就会计数+1
        redisTemplate.opsForValue().increment(uri);
        return true;
    }
}
#######################################WebMvcConfigurer############################
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
    /**
     * Filter、Interceptor 几乎拥有相同的功能?
     * 1、Filter是Servlet定义的原生组件。好处,脱离Spring应用也能使用
     * 2、Interceptor是Spring定义的接口。可以使用Spring的自动装配等功能
     *
     */
 @Autowired
    RedisUrlCountInterceptor redisUrlCountInterceptor;
@Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()) //登录注册拦截器
                .addPathPatterns("/**")// 所有的请求都被拦截器拦截,包括静态资源  /**中 * 单级目录,/**代表多级目录.不能直接使用/*/*
                .excludePathPatterns("/", "/login","/error", "/css/**", "/fonts/**", "/images/**", "/js/**");//放行的请求.
        //这里一定要使用注入的,使用new 的,里面的东西都为空...
        registry.addInterceptor(redisUrlCountInterceptor).addPathPatterns("/**")
                .excludePathPatterns("/", "/login","/error", "/css/**", "/fonts/**", "/images/**", "/js/**");
    }
}
################################Controller##########################################
@Slf4j
@Controller
public class IndexController {
   @GetMapping("/main.html")
    public String mainPage(HttpSession session,Model model){
        log.info("当前方法是:{}","mainPage");
        // // 是否登录  拦截器,过滤器
        // Object loginUser = session.getAttribute("loginUser");
        // if(loginUser!=null){
        //     return "main";
        // }else{
        //     //回到登录页面
        //     model.addAttribute("msg","请重新登录");
        //     return "login";
        // }
        ValueOperations <String, String> operations = redisTemplate.opsForValue();
        String s = operations.get("/main.html");
        String s1 = operations.get("/sql");
        model.addAttribute("mainCount", s);
        model.addAttribute("sqlCount", s1);
        return "main";
        //这中间的所有拦截操作,可以交给拦截器来搞.
    }
}
###########################main.html###############################################
  <div class="col-xs-8">
      <span class="state-title" th:text="${mainCount}">  New Order  </span>
       <h4>\main.html</h4>
 </div>
<div class="col-xs-8">
     <span class="state-title" th:text="${sqlCount}">  Unique Visitors  </span>
       <h4>/sql</h4>
 </div>

运行结果:

84984ebe09ef409daf698b51a81d1779.png

832d7cbee7134c98b4b39f57e54a7fd0.png

86c7f8ba42c24aaea8851c4f14e1be14.png




相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
ly~
|
18天前
|
数据库 数据库管理
数据库的事务处理机制有哪些优点?
数据库的事务处理机制具备多种优势:首先,它能确保数据一致性,通过原子性保证所有操作全成功或全失败,利用完整性约束维护数据的有效性;其次,增强了系统可靠性,提供故障恢复能力和正确处理并发操作的功能;最后,简化了应用程序开发工作,将操作封装为逻辑单元并集中处理错误,降低了开发复杂度。
ly~
18 1
|
3月前
|
SQL 开发框架 关系型数据库
基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中
基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中
|
3月前
|
开发框架 前端开发 测试技术
基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中(2)
基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中(2)
|
SQL Java 数据库连接
Spring框架数据访问
Spring框架数据访问
62 1
|
SQL PHP 数据库
|
Oracle 关系型数据库 数据库
两个数据访问受限的问题
    最近几天实在忙得厉害,处理了各种数据需求,有种顾及不来,而其中有一部分问题是和数据访问相关的,问题的原因很简单,但是分析问题的过程就需要很多的经验,推导,比如下面的两个案例。
992 0