SSM框架学习——SqlSession以及Spring与MyBatis整合

news2024/11/28 14:43:18

SqlSession以及Spring与MyBatis整合

准备所需要的JAR包

要实现MyBatis与Spring的整合,很明显需要这两个框架的JAR包,但是只是使用这两个框架中所提供的JAR包是不够的,还需要配合其他包使用:

  • Spring的JAR包
  • MyBatis的JAR包
  • Spring与MyBatis整合中间包mybatis-spring-x.x.x.jar
  • 数据库驱动JAR(以MYSQL为例)mysql-connector-java-x.x.x-bin.jar
  • 数据源所需的JAR(DBCP)commons-dbcp2-x.x.x.jarcommons-pool2-x.x.x.jar

配置文件介绍

关于resources文件夹

我们在之前的项目中,几乎每次都会创建这个文件夹,然后Use as a source folder,那么这个文件夹到底是用来干啥的,凭什么使用它里面的文件是直接写文件名?

实际上这个文件夹是专门存放你的应用所需资源的,如XML等配置文件。这个文件夹被标记为source folder后,在编译后,里面的文件会放到与编译好的文件相同目录里,所以你读取的直接使用文件名实际上是相对路径。

pom.xml

如果我们创建的是一个Maven项目,就可以在pom.xml里添加<properties></properties>标签来定义库版本,然后在下方的<dependencies></dependencies>中的<dependency></dependency><version></version>${...}形式引用它。

下面的XML文件省略了很多,仅为了演示。

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <junit.version>4.12</junit.version>

    <!-- 此处表示省略 -->
    [...]
</properties>

<dependencies>
    <!-- JUINT -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <!-- 引用上方标签的版本号 -->
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>

    <!-- 此处表示省略 -->
    [...]
</dependencies>

db.properties

db.properties主要包含一些数据库连接信息,比如JDBC连接驱动、数据库账户名和密码等。

我们在之前的项目中就已经使用过这个文件了,但我们一直没有详细介绍过其每条内容的含义(实际上语义很明显)

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis?useUnicode=true&characterEncoding=utf8
jdbc.username=db_mybatis
jdbc.password=db_mybatis

首先第一行jdbc.driver是指定数据库连接驱动。JDBC即Java数据库连接,它定义了一套关系型数据库的规则,没错实际上就是接口,然后实现并不是由Java官方进行的,而是交给各个数据库厂商来做,它们打包的库也就是JAR包,就被叫做数据库驱动,同时也意味着不同数据库就有不同的驱动实现。

程序设计者无需去关心每个数据库驱动是怎么实现的,而是像你把手机充电器插到墙上的插座一样,把驱动按照接口给“插”进去。这就是面向接口编程的好处。

你的程序只是一个调用者,数据库驱动就像一个代理人,你要先告诉这个代理人怎么操作,然后让这个代理人去真正操纵数据库(怎么操纵你是不关心的,只要满足你的操作需求即可)。你与这个代理人约定的通用交流方式就是刚才的接口,而代理人具体的操纵方式就是驱动的实现。

我们所给的代码中很显然是MySQL的数据库驱动,后面的mysql.jdbc.Driver实际上是随你pom.xml添加的包一块引入的。

第二行的是数据库连接URL,它实际上是数据库JDBC连接字符串的一部分。它的书写形式应该参考数据库驱动提供方的文档!

  • jdbc说明这是一个JDBC的连接字符串
  • mysql说明连接的数据库为MYSQL
  • localhost所在部分,一般是数据库的网络地址或域名,localhost实际上是一个域名,它在你系统的HOST文件中被解析到了127.0.0.1(通常是这样,不绝对,你完全可以修改它),这个地址是一个回环地址,它实际上表示你机器本身。同理,我的MySQL如果在远程服务器192.168.10.2上面,这里就不再是localhost,而是192.168.10.2或者对应的域名。
  • db_mybatis部分对应数据库名称,这个我们在之前创建过。
  • useUnicode这里的值为true表示使用Unicode编码,它是国际标准字符集,将世界上每一种自然语言每个字符都定义为一个唯一编码,满足跨语言需要,尤其是包含中文的时候。
  • characterEncoding部分是指定Unicode编码的存储方式。Unicode只是一个符号集,但并没有规定怎么存放。这里的存放方式为utf8,被定义为将码点编码为1到4个字节byte,具体取决于有效二进制位的数量。

类似于useUnicode的参数还有很多,比如设置SSL等,这里不过多介绍,碰到了请参考文档或搜索引擎。

jdbc.usernamejdbc.password就很简单了,一般是具有权限的数据库用户的用户名和密码。分配一个或多个具有部分权限的用户是好习惯,而不是一直用root(它权限太大了,不安全)。

app.xml

app.xml为Spring配置文件,名称同样不固定,根据你自己来。对于内容的解释请看下方代码的注释:

<!-- 指定XML版本和编码方式为Unicode UTF-8 -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx.xsd
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 指定需要扫描的包,使注解生效 -->
    <context:component-scan
        base-package="xxx.xxxx.xxx" />
    <!--读取db.properties -->
    <context:property-placeholder location="classpath:db.properties"/>
    <!-- 配置数据源 -->
    <bean id="dataSource" 
            class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!--数据库驱动 -->
        <property name="driverClassName" value="${jdbc.driver}" />
        <!--连接数据库的url -->
        <property name="url" value="${jdbc.url}" />
        <!--连接数据库的用户名 -->
        <property name="username" value="${jdbc.username}" />
        <!--连接数据库的密码 -->
        <property name="password" value="${jdbc.password}" />
    </bean>

    <!-- 事务管理器,依赖于数据源 -->
    <bean id="transactionManager" class=
     "org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>	
    <!-- 注册事务管理器驱动,开启事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- 配置MyBatis工厂 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 这里指定了MyBatis配置文件为mybatis-config.xml -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
   </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="xx.xxx.xx.mapper" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>

</beans>

mybatis-config.xml

mybatis-config.xml为MyBatis配置文件,当然你可以不写它,将它的配置写在Spring配置文件中(写法不太一样),但不建议这么做,当文件内容特别多时不利于维护。

<?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>
        <!-- 延迟加载的开关 -->
        <setting name="lazyLoadingEnabled" value="false" />
        <!-- 设置积极加载(true)或按需加载(false) -->
        <setting name="aggressiveLazyLoading" value="true" />
        <setting name="mapUnderscoreToCamelCase" value="true" />
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>
    <typeAliases>
        <!-- 对应的dao实体对象 -->
        <package name="xx.xxx.xx.dao" />
    </typeAliases>
    <!--2.配置Mapper的位置 -->
    <mappers>
        <mapper resource="xx/xxx/xx/mapper/CustomerMapper.xml" />
    </mappers>
</configuration>

log4j.properties

日志的配置文件

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.top.cairbin.test5=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

进程、线程与CPU调度

在开始Spring与MyBatis的整合之前,为了了解一些概念,我们来讲下进程与线程。

什么是进程?进程是对程序过程的抽象。它是OS的动态执行单元,在传统OS上既是基本分配单元又是基本执行单元。

举个不太严谨的例子,你在Windows下打开一个音乐播放器,随之你能在任务管理器中看到这一项,而这个正在运行的音乐播放器就是一个进程。

线程实际上算是轻量级的进程,但二者还是不太相同,不过它们的相同点要多余不同点。它是看起来就像是对计算机创建进程的模拟,只不过这个模拟是在进程之中的。

进程内存资源相对来讲较独立,而多个线程共享进程的内存资源。

另外我们的CPU调度一般是抢占式的,我们在使用计算机的时候看起来没啥感觉,但实际上CPU一直在“抽疯”——在多个线程之间进行高速切换,这就带来一些问题。

有些操作它不是原子的,即可分割为更小的操作,当一个活没有干完的时候,CPU便去干另一个活。

同时,多个线程尝试对同一个变量进行修改的时候,顺序可能是乱的。

这些都有可能导致线程不安全。什么是线程不安全?指多线程并发执行某个代码的时候,产生了逻辑上的错误,结果与预期值不同。

当然,内存可变性以及Java编译器对指令优化也有可能导致这种情况。

SqlSession

对于MyBatis来讲实际上有三种SqlSession,我们来分别讲讲它们的区别和使用场景。

首先看一张图片,描述再来描述它们的关系:

DefaultSqlSession

DefaultSqlSession类是SqlSession接口的默认实现,它通常被使用于执行SQL操作数据库。

//读取配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

// 构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();

try {
    MyDao myDao = sqlSession.selectOne("MyMapper.selectDao", 1);
    System.out.println(myDao);
} finally {
     sqlSession.close();
}

DefaultSqlSession是一个线程不安全的,也就是说它不能是单例。

啥是单例?某些组件在整个程序运行时只要一个实例对象,多个实例化可能会报错。

DefaultSqlSession即然不能是单例,那每次从工厂中获取一个不就行了,实际上这会带来额外开销和资源重用。

另外,DefaultSqlSession还需要手动调用close()方法,这很容易忘记(虽然对于C++程序员是家常便饭),但是聪明的你肯定能用我们所学过的东西来解决这一问题吧——没错就是AOP。

我们既想要单例,又要线程安全,还想要自动关闭怎么办?这就有了SqlSessionManager

SqlSessionManager

SqlSessionManager使用了JDK动态代理技术(我们之前讲过),动态生成代理对象sqlSessionProxy,并通过SqlSessionInterceptor来对DefaultSqlSession进行增强。

虽然对于SqlSessionManager实际上还是创建非单例的DefaultSqlSession来执行方法,但SqlSessionManager可以是单例!

那你可能会怼我,说多个DefaultSqlSession这不还是会造成额外开销和资源重用吗?SqlSessionManager还有另外一种形态,它会复用线程本地的DefaultSqlSession

线程不安全是由于多个线程之间共享DefaultSqlSession导致的,那我在同线程内“共享”(复用)我自己的DefaultSqlSession那不就解决线程安全问题了吗。这就大大提高了效率。

治不了洋人还治不了你吗(雾)!

SqlSessionTemplate

SqlSessionTemplate是MyBatis与Spring整合时的线程安全SqlSession

SqlSessionTemplate实现线程安全的思路与SqlSessionManager相反,我既然自己管不了,我就让别人管——它交给SqlSessionUtils去获取SqlSession

但从本质上讲SqlSessionTemplateSqlSessionManager还是一样的。

SqlSessionUtils会先尝试从事务同步器中获取,获取不到再从工厂里要。而事务同步器本身就是一个线程本地变量管理器。

所以SqlSessionTemplateSqlSessionManager在实现线程安全这一点上殊途同归。

但是二者在自动关闭,即自动执行close()方法的时候就有区别了。

SqlSessionTemplate分两种情况:

  • 当获取的对象由事务同步管理器返回的时候,那关闭是交给Spring的。
  • 如果是从工厂里拿的,直接调用close()方法。

Spring与MyBatis整合

Spring与MyBatis整合方式分为两种:

  • 传统Dao方式
  • Mapper接口方式

传统Dao方式整合

采用传统的Dao方式整合Spring和MyBatis框架,可采用mybatis-spring中所提供的SqlSessionTemplate类或者SqlSessionDaoSupport类来实现。

由于这种方式在现在的开发中已经不常用了,所以这里仅做演示。

@Repository
public class CustomerDaoImpl extends SqlSessionDaoSupport implements ICustomerDao{
    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory){
        super.sqlSessionFactory = sqlSessionFactory;
    }

    public void add(Customer customer){
        [...]
    }
}

更细化的讲解可参考Spring | 整合MyBatis中SqlSessionTemplate和MapperScannerConfigurer类的使用

Mapper接口方式

传统Dao方式会产生大量重复代码,而且需要正确指定映射文件中的id。

为了解决上述问题,我们采用Mapper的方式整合开发。

基于MapperFactoryBean的整合

MapperFactoryBean是MyBatis-Spring团队提供的一个用来根据Mapper接口生成Mapper对象的类,该类在配置文件中使用时可以配置一下参数

  • mapperInterface用于指定接口
  • SqlSessionFactory用于指定SqlSessionFactory
  • SqlSessionTemplate用于指定SqlSessionTemplate,如果与SqlSessionFactory同时设定,则一般情况下只会启用SqlSessionTemplate。

虽然使用Mapper接口编程的方式很简单,但是在具体使用的时候还是需要遵循一些规范:

  • Mapper接口的名称和对应的XML映射文件名称必须一致
  • XML映射文件中的namespace与Mapper接口的类路径相同
  • Mapper接口方法名要和XML映射文件中定义的每个执行语句的id相同
  • Mapper接口中的方法的输入参数类型和XML映射文件中的parameterType类型相同
  • Mapper接口方法的输出类型要和XML映射文件的resultType类型相同
基于MapperScannerConfigurer的方式

使用上面的方式会使得配置文件臃肿,所以我们在做项目开发的时候一般是使用MapperScannerCongigurer的方式进行扫描。

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="top.cairbin.test6.mapper" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>

我们新建一个项目top.cairbin.test6,至于哪些细节该注意你应当非常清楚了,这里就不多说了,如果不会请回去看之前的教程。

对于配置文件我们也说的很清楚了,接下来直接给文件:

pom.xml文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>top.cairbin</groupId>
  <artifactId>test6</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>test6</name>
  <url>http://maven.apache.org</url>

 	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>1.7</maven.compiler.source>
		<maven.compiler.target>1.7</maven.compiler.target>
		<junit.version>4.12</junit.version>
		<spring.version>5.2.5.RELEASE</spring.version>
		<mybatis.version>3.5.4</mybatis.version>
		<mybatis.spring.version>2.0.4</mybatis.spring.version>
		<mysql.version>8.0.33</mysql.version>
		<commons-dbcp.version>2.7.0</commons-dbcp.version>
	</properties>

  <dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>		
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>${mybatis.version}</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>${mybatis.spring.version}</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
			<version>${commons-dbcp.version}</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis.generator</groupId>
			<artifactId>mybatis-generator-core</artifactId>
			<version>1.4.0</version>
		</dependency>		
	</dependencies>
</project>

db.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis?useUnicode=true&characterEncoding=utf8
jdbc.username=db_mybatis
jdbc.password=db_mybatis

Spring配置文件app.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx.xsd
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 指定需要扫描的包,使注解生效 -->
	<context:component-scan
		base-package="top.cairbin.test6" />
	<!--读取db.properties -->
    <context:property-placeholder location="db.properties"/>
    <!-- 配置数据源 -->
	<bean id="dataSource" 
            class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!--数据库驱动 -->
        <property name="driverClassName" value="${jdbc.driver}" />
        <!--连接数据库的url -->
        <property name="url" value="${jdbc.url}" />
        <!--连接数据库的用户名 -->
        <property name="username" value="${jdbc.username}" />
        <!--连接数据库的密码 -->
        <property name="password" value="${jdbc.password}" />
	</bean>

<!-- 事务管理器,依赖于数据源 -->
	<bean id="transactionManager" class=
     "org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>	
    <!-- 注册事务管理器驱动 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
                 <property name="dataSource" ref="dataSource" />
                 <property name="configLocation" value="mybatis-config.xml"/>
   </bean>
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="top.cairbin.test6.mapper" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>
</beans>

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>
		<!-- 延迟加载的开关 -->
		<setting name="lazyLoadingEnabled" value="false" />
		<!-- 设置积极加载(true)或按需加载(false) -->
		<setting name="aggressiveLazyLoading" value="true" />
		<setting name="mapUnderscoreToCamelCase" value="true" />
		<setting name="logImpl" value="STDOUT_LOGGING" />
	</settings>

	<typeAliases>
		<package name="top.cairbin.test6.dao" />
	</typeAliases>

	<!--2.配置Mapper的位置 -->
	<mappers>
		<mapper resource="top/cairbin/test6/mapper/CustomerMapper.xml" />
	</mappers>
</configuration>

top.cairbin.test6.dao.Customer

package top.cairbin.test6.dao;

public class Customer {
	private Integer id;			// 主键id
	private String username;	// 客户名称
	private String jobs;		// 职业
	private String phone;		// 电话
	
	public Integer getId() {
		return this.id;
	}
	
	public void setId(Integer id) {
		this.id = id;
	}
	
	public String getUsername() {
		return this.username;
	}
	
	public void setUsername(String username) {
		this.username = username;
	}
	
	public String getJobs() {
		return this.jobs;
	}
	
	public void setJobs(String jobs) {
		this.jobs = jobs;
	}
	
	public String getPhone() {
		return this.phone;
	}
	
	public void setPhone(String phone) {
		this.phone = phone;
	}
	
	@Override
	public String toString() {
		return "Customer [id=" + id + ", username=" + username + 
				       ", jobs=" + jobs + ", phone=" + phone + "]";
	}
}

top.cairbin.test6.mapper下的CustomerMapper.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.cairbin.test6.mapper.CustomerMapper">
	<resultMap id="BaseResultMap" type="top.cairbin.test6.dao.Customer">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="username" jdbcType="VARCHAR" property="username" />
    <result column="jobs" jdbcType="VARCHAR" property="jobs" />
    <result column="phone" jdbcType="VARCHAR" property="phone" />
  </resultMap>
  <sql id="Base_Column_List">
    id, username, jobs, phone
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from customer
    where id = #{id,jdbcType=INTEGER}
  </select>
</mapper>

对应接口top.cairbin.test6.mapper.CustomerMapper

package top.cairbin.test6.mapper;

import top.cairbin.test6.dao.Customer;

public interface CustomerMapper{
	// 通过id查询客户
	Customer selectByPrimaryKey(Integer id);
}

我们接下来实现Service层

创建src/main/java下的包top.cairbin.test6.service

然后在包中创建接口ICustomerService

package top.cairbin.test6.service;

import top.cairbin.test6.dao.Customer;

public interface ICustomerService {	
	public Customer getCustomerByID(int id);
}

创建实现这个接口的类CustomerServiceImpl

package top.cairbin.test6.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.cairbin.test6.dao.Customer;
import top.cairbin.test6.mapper.CustomerMapper;

@Service
public class CustomerServiceImpl implements ICustomerService{
	@Autowired
	private CustomerMapper customerMapper;

	public Customer getCustomerByID(int id) {
		Customer customer = customerMapper.selectByPrimaryKey(id);
		return customer;
	}
}

在测试目录src/test/java下的top.cairbin.test6包创建测试类CustomerTest

package top.cairbin.test6;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import top.cairbin.test6.dao.Customer;
import top.cairbin.test6.service.ICustomerService;


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:app.xml" })
public class CustomerTest {

	@Autowired
	private ICustomerService customerService;	
	@Test
	public void findTest() {
		Customer customer = customerService.getCustomerByID(1);
		System.out.println(customer);
	}
}

运行测试,得到结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1562474.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是人工智能物联网(AIoT)?

过去十年&#xff0c;从医疗设备、家庭和楼宇自动化到工业自动化等各个领域&#xff0c;物联网 (IoT) 设备的数量呈爆炸式增长。设备包括可穿戴设备、传感器、电器和医疗监视器——所有这些设备都相互连接&#xff0c;收集和共享大量数据。国际数据公司 (IDC) 预测&#xff0c;…

LuaJIT源码分析(二)数据类型

LuaJIT源码分析&#xff08;二&#xff09;数据类型 LuaJIT支持的lua数据类型和官方的lua 5.1版本保持一致&#xff0c;它的源文件中也有一个lua.h&#xff1a; // lua.h /* ** basic types */ #define LUA_TNONE (-1)#define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define L…

将 Three 带到 Vue 生态系统,TresJs 中文文档上线

将 Three 带到 Vue 生态系统&#xff0c;TresJs 中文文档上线 中文文档上线入门指南 ThreeJS 在创建 WebGL 3D 网站方面是一个奇妙的库&#xff0c;同时他也是一个保持不断更新的库&#xff0c;一些对其封装的维护者&#xff0c;如 TroisJS&#xff0c;往往很难跟上其所有的更…

在js中本地存储的数组如何转成对象

一、此方法仅适用一维数组&#xff1b; 二、效果图 使用后 三、js代码。 function gong(s){console.log(s);let data;let kk1;// 检查ask_id是否不为空 if (s.ask_id null ) { kk1}else{kk2let dd;dds.data;sessionStorage.setItem(wenda,JSON.stringify(dd[0]))window.l…

个人简历主页搭建系列-05:部署至 Github

前面只是本地成功部署网站&#xff0c;网站运行的时候我们可以通过 localhost: port 进行访问。不过其他人是无法访问我们本机部署的网站的。 接下来通过 Github Pages 服务把网站部署上去&#xff0c;这样大家都可以通过特定域名访问我的网站了&#xff01; 创建要部署的仓库…

【Go】十三、面向对象:方法

文章目录 1、面向对象2、结构体实例的创建3、结构体之间的转换4、方法5、结构体值拷贝6、方法的注意点7、方法和函数的区别8、跨包创建结构体实例 1、面向对象 Go的结构体struct ⇒ Java的Class类Go基于struct来实现OOP相比Java&#xff0c;Go去掉了方法重载、构造函数和析构函…

[Java基础揉碎]枚举

目录 先看一个需求 枚举介绍: 枚举实现的方式: >自定义类实现枚举实例: >使用enum关键字实现枚举 ​编辑 enum关键字实现枚举注意事项 enum常用方法 enum细节 先看一个需求 要求创建季节(Season)对象&#xff0c;请设计并完成。 // 传统的方法建造一个类: clas…

企业能耗数据分析有哪些优势?怎样进行分析?

随着互联网技术的发展&#xff0c;企业在运营中会出现大量的用能数据&#xff0c;但却做不了精准的用能数据分析&#xff0c;导致数据没有得到有效利用&#xff0c;以及产生能源浪费现象。 为什么企业用能分析总是难&#xff1f; 一、用能分析过程复杂 由于用能分析过于复杂…

websocketpp上手笔记-Windows安装

WebSocketpp是什么 最近手上有一个c项目&#xff0c;需要用websocket从服务器端收内容。于是网上找了圈&#xff0c;发现WebSocketpp库可以做websocket的客户端。 WebSocketpp也叫WebSocket&#xff0c;github地址是&#xff1a;https://github.com/zaphoyd/websocketpp&…

每天五分钟深度学习:神经网络和深度学习有什么样的关系?

本文重点 神经网络是一种模拟人脑神经元连接方式的计算模型&#xff0c;通过大量神经元之间的连接和权重调整&#xff0c;实现对输入数据的处理和分析。而深度学习则是神经网络的一种特殊形式&#xff0c;它通过构建深层次的神经网络结构&#xff0c;实现对复杂数据的深度学习…

商标名称的词性:因形近不良而驳回!

近期看到业内有许多因不良驳回的案例&#xff0c;有些是直接因为不良而驳回&#xff0c;普推知产老杨发现一个因形近而驳回的案例&#xff0c;2022年5月申请的“乡巴佬”通过初审下证了&#xff0c;2022年10月申请“乡巴饶”因形近“乡巴佬”不良而驳回&#xff0c;而且还做过驳…

打造安全医疗网络:三网整体规划与云数据中心构建策略

医院网络安全问题涉及到医院日常管理多个方面&#xff0c;一旦医院信息管理系统在正常运行过程中受到外部恶意攻击&#xff0c;或者出现意外中断等情况&#xff0c;都会造成海量医疗数据信息的丢失。由于医院信息管理系统中存储了大量患者个人信息和治疗方案信息等&#xff0c;…

Word、Excel、PPT文件转PDF文件(C#)

一、添加依赖 为wpf项目引用Microsoft.Office.Interop.Excel、Microsoft.Office.Interop.PowerPoint、Microsoft.Office.Interop.Word、Office&#xff0c;依赖文件已经打到源代码包里了。 二、先定义一些命名空间 using Word Microsoft.Office.Interop.Word;using Excel M…

Vue2.x安装Tinymce依赖冲突解决

Vue2.x安装Tinymce依赖冲突原因 使用vue整合tinymce富文本编辑器&#xff0c;安装依赖时报错 报错的原因是下载版本与vue的版本对不上vue2.x版本应该使用如下指定版本依赖更合适 npm install --save "tinymce/tinymce-vue^3.1"额外依赖为 npm install --save &quo…

ssm013小型企业办公自动化系统的设计和开发+vue

小型企业办公自动化系统的设计与实现 摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对小型企业办公信息管理混乱&am…

流行的API架构学习

几种流行的API架构风格图 SOAP&#xff08;Simple Object Access Protocol&#xff09; 优点&#xff1a;SOAP 是一种基于 XML 的通信协议&#xff0c;具有良好的跨平台和跨语言支持。它提供了丰富的安全性和事务管理功能&#xff0c;并支持复杂的消息交换模式。 缺点&#xf…

远控桌面多任务并发文件保密传输

远程桌面文件传输是一个重要的功能&#xff0c;大多数远控都是用的桌面程序模式&#xff0c;利用系统自带复制粘贴拖拽文件拷贝功能&#xff0c;做一个ole调用对接&#xff0c;可以将很多控制权交给操作系统。 但我做的是浏览器版&#xff0c;浏览器是沙盒原理&#xff0c;为了…

mkcert生成ssl证书+nginx部署局域网内的https服务访问问题

文章目录 mkcert生成ssl证书nginx部署局域网内的https服务访问问题1、下载mkcert查看自己的电脑是arm还是amd架构 2、安装mkcert3、测试mkcert是否安装成功4、查看CA证书存放位置5、打开windows的证书控制台6、生成自签证书,可供局域网内使用其他主机访问以下是nginx部署https服…

代码随想录第27天 | 39. 组合总和、40.组合总和II、131.分割回文串

一、前言 今天的主题还是回溯算法&#xff0c;还是根据那个backtracking模板&#xff0c;但是今天会涉及到去重和一些小细节的问题。 二、组合总和 1、思路&#xff1a; 我一开始的想法就是在for循环转化为&#xff1a; for(int i 0; i < size; i) 但是这个是会陷入一…

【LDLTS】拉普拉斯深能级瞬态光谱

Laplace deep level transient spectroscopy&#xff08;拉普拉斯深能级瞬态光谱&#xff0c;简称LDLTS&#xff09;是一种用于分析和表征半导体材料中深层能级缺陷的技术。它是传统能级瞬态光谱&#xff08;DLTS&#xff09;方法的扩展和改进&#xff0c;特别适用于解决传统DL…