在J2EE领域,Hibernate与Mybatis是大家常用的持久层框架,它们各有特点,在持久层框架中处于领导地位。

本文主要介绍Mybatis(对于较小型的系统,特别是报表较多的系统,个人偏向Mybatis),对于它,个人比较喜欢的是:

  • 使用简单、方便;
  • 支持的XML动态SQL的编写,方便浏览、修改,同时降低SQL与应用程序之间的耦合。

不喜欢的是:

  • 出现错误时,调试不太方便

本文主要介绍Mybatis的搭建,是学习Mybatis过程后整理的札记,其中包括“单独搭建Mybaits”和常用的“Mybatis与Spring的整合”。

一、数据库的准备

因为Mybatis是持久层框架,毫无疑问,是需要操作数据库的。所以,在搭建之前,我们需要先创建一个简单的表。

SQL - DDL - Create Table
create table T_USER_TEST_1407
(USERNAME VARCHAR2(255),PASSWORD VARCHAR2(255)
)

插入一些数据,以作查询的测试。

insert into T_USER_TEST_1407 (USERNAME, PASSWORD)
values ('nick', 'Optimistic,Confident,Love - 1');
insert into T_USER_TEST_1407 (USERNAME, PASSWORD)
values ('nick', 'Optimistic,Confident,Love - 1');

二、单独搭建Mybaits

1)环境准备、版本说明

此工程使用JDK1.6 + mybatis-3.2.4 + Oracle11g。

新建一个Web工程,由于只构建Mybatis,只引用Mybatis和Oracle JDBC驱动包

  • mybatis-3.2.4.jar
  • ojdbc6.jar

2)程序的搭建

首先,我们将数据源等配置信息放在一个xml,让Mybatis可以根据这个信息去连接数据库、管理事务。

目前我们可只关注environments节点,此节点是用于配置数据源、事务管理的 。

其他的节点,如typeAliases、mappers,是用于注册一些信息的,后面会陆续提到。

<?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>

<!-- Register Alias -->
<typeAliases>
<typeAlias alias="user" type="com.nicchagil.mybatisonly.bean.User" />
</typeAliases>

<!-- Data Source -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@xxx.xxx.xxx.xxx:xxxx:xxxxxx" />
<property name="username" value="xxxx" />
<property name="password" value="xxxx" />
</dataSource>
</environment>
</environments>

<!-- Register Mapper -->
<mappers>
<!-- SQL Mapper -->
<mapper resource="com/nicchagil/mybatisonly/mapper/sqlxml/UserMapper.xml" />
</mappers>

</configuration>

mybatis-config.xml

 1 <?xml version="1.0" encoding="UTF-8" ?>2 <!DOCTYPE configuration3   PUBLIC "-//mybatis.org//DTD Config 3.0//EN"4   "http://mybatis.org/dtd/mybatis-3-config.dtd">5   6 <configuration>7 8     <!-- Register Alias -->9     <typeAliases>
10         <typeAlias alias="user" type="com.nicchagil.mybatisonly.bean.User" />
11     </typeAliases>
12
13     <!-- Data Source -->
14     <environments default="development">
15         <environment id="development">
16             <transactionManager type="JDBC" />
17             <dataSource type="POOLED">
18                 <property name="driver" value="oracle.jdbc.driver.OracleDriver" />
19                 <property name="url" value="jdbc:oracle:thin:@xxx.xxx.xxx.xxx:xxxx:xxxxxx" />
20                 <property name="username" value="xxxx" />
21                 <property name="password" value="xxxx" />
22             </dataSource>
23         </environment>
24     </environments>
25
26     <!-- Register Mapper -->
27     <mappers>
28         <!-- SQL Mapper -->
29         <mapper resource="com/nicchagil/mybatisonly/mapper/sqlxml/UserMapper.xml" />
30     </mappers>
31
32 </configuration>

既然有了配置的xml,下一步就需要让Mybatis加载它了。

  1. 首先以输入流的形式加载xml
  2. 以“SqlSessionFactoryBuilder -> SqlSessionFactory -> SqlSession”的流程最后构建出SqlSession。
    • SqlSession,顾名思义,是一次会话,是应用程序与数据库交互的会话,所以,其生命周期应在一次数据库连接之间,当然,此次数据库连接可以包含一次或多次数据库操作。
    • SqlSessionFactory,顾名思义,是SqlSession的工厂类,用于产出SqlSession。我们知道,SqlSession主要用于数据库操作,而数据库操作又是贯穿于应用程序整个生命周期当中的,那么,"产出SqlSession"这个动作也应当贯穿于应用程序整个生命周期当中,所以,SqlSessionFactory的生命周期一般为应用程序的整个生命周期,一般为单例/static的形式存在。
    • SqlSessionFactoryBuilder,由代码可见,其主要作用是从配置文件中获取配置信息,然后构建SqlSessionFactory,所以其生命周期可以是临时的,局部的。
  3. 通过SqlSession获取UserMapper接口,再调用该接口的数据操纵方法。
Call

package com.nicchagil.mybatisonly;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.nicchagil.mybatisonly.bean.User;
import com.nicchagil.mybatisonly.mapper.UserMapper;

public class Call {

public static SqlSessionFactory sqlSessionFactory = null;

public static void main(String[] args) throws IOException {

// Query User
/*
kickStartMybatis();
queryUser("nick");
*/

// Inser User
kickStartMybatis();
insertUser("user004", "hello world.");

}

public static void kickStartMybatis() throws IOException {
String resource = "com/nicchagil/mybatisonly/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}

/**
* Query User
* @param username
* @return
*/
public static User queryUser(String username) {

User user = null;
SqlSession session = sqlSessionFactory.openSession();
try {

/* Un-recommended Method */
/*
user = (User)session.selectOne("com.nicchagil.mybatisonly.mapper.UserMapper.queryUser", username);
*/

/* Recommended Method */
UserMapper userMapper = session.getMapper(UserMapper.class);
user = userMapper.queryUser(username);

System.out.println("username - " + user.getUsername() + " , password - " + user.getPassword());

} finally {
session.close();
}

return user;
}

/**
* Insert User
* @param username
* @param password
*/
public static void insertUser(String username, String password) {

SqlSession session = sqlSessionFactory.openSession();

try {

UserMapper userMapper = session.getMapper(UserMapper.class);

User user = new User();
user.setUsername(username);
user.setPassword(password);

userMapper.insertUser(user);

// Flushes batch statements and commits database connection.
// Note that database connection will not be committed if no updates/deletes/inserts were called.
session.commit();

System.out.println("username - " + user.getUsername() + " , password - " + user.getPassword());

} catch (Exception e) {
session.rollback();
e.printStackTrace();

//TODO Print the exception logs
//TODO Prompts fail to execute for user

} finally {
session.close();
}

}

/**
* Insert User
* @param username
* @param password
*/
public static void insertUserBySQL(String username, String password) {

SqlSession session = sqlSessionFactory.openSession();

try {

User user = new User();
user.setUsername(username);
user.setPassword(password);

session.insert("com.nicchagil.mybatisonly.mapper.UserMapper.insertUser", user);

// Flushes batch statements and commits database connection.
// Note that database connection will not be committed if no updates/deletes/inserts were called.
session.commit();

} catch (Exception e) {
session.rollback();
e.printStackTrace();

//TODO Print the exception logs
//TODO Prompts fail to execute for user

} finally {
session.close();
}

}

}

Call

package com.nicchagil.mybatisonly;import java.io.IOException;
import java.io.InputStream;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import com.nicchagil.mybatisonly.bean.User;
import com.nicchagil.mybatisonly.mapper.UserMapper;public class Call {public static SqlSessionFactory sqlSessionFactory = null;public static void main(String[] args) throws IOException {// Query User/*kickStartMybatis();queryUser("nick");*/// Inser UserkickStartMybatis();insertUser("user004", "hello world.");}public static void kickStartMybatis() throws IOException {String resource = "com/nicchagil/mybatisonly/mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}/*** Query User* @param username* @return*/public static User queryUser(String username) {User user = null;SqlSession session = sqlSessionFactory.openSession();try {/* Un-recommended Method *//*user = (User)session.selectOne("com.nicchagil.mybatisonly.mapper.UserMapper.queryUser", username);*//* Recommended Method */UserMapper userMapper = session.getMapper(UserMapper.class);user = userMapper.queryUser(username);System.out.println("username - " + user.getUsername() + " , password - " + user.getPassword());} finally {session.close();}return user;}/*** Insert User* @param username* @param password*/public static void insertUser(String username, String password) {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);User user = new User();user.setUsername(username);user.setPassword(password);userMapper.insertUser(user);// Flushes batch statements and commits database connection. // Note that database connection will not be committed if no updates/deletes/inserts were called.session.commit();System.out.println("username - " + user.getUsername() + " , password - " + user.getPassword());} catch (Exception e) {session.rollback();e.printStackTrace();//TODO Print the exception logs//TODO Prompts fail to execute for user} finally {session.close();}}/*** Insert User* @param username* @param password*/public static void insertUserBySQL(String username, String password) {SqlSession session = sqlSessionFactory.openSession();try {User user = new User();user.setUsername(username);user.setPassword(password);session.insert("com.nicchagil.mybatisonly.mapper.UserMapper.insertUser", user);// Flushes batch statements and commits database connection. // Note that database connection will not be committed if no updates/deletes/inserts were called.session.commit();} catch (Exception e) {session.rollback();e.printStackTrace();//TODO Print the exception logs//TODO Prompts fail to execute for user} finally {session.close();}}}

UserMapper是一个DAO的接口,是定义作哪些数据库操作的。

UserMapper.java

package com.nicchagil.mybatisonly.mapper;

import com.nicchagil.mybatisonly.bean.User;

public interface UserMapper {

public User queryUser(String username);

}

1 package com.nicchagil.mybatisonly.mapper;
2
3 import com.nicchagil.mybatisonly.bean.User;
4
5 public interface UserMapper {
6
7     public User queryUser(String username);
8
9 }

UserMapper只是供调用的接口,那么具体的实现逻辑在哪里呢?

我们可见UserMaper.xml,它定义的SQL就是用于定义UserMapper接口的实现。我们需在mybatis-config.xml注册UserMaper.xml,可见mybatis-config.xml的mappers节点。

  • 我们可以看到id为queryUser,与接口的方法名对应;
  • SQL我们很熟悉了,就是一个简单的SQL,而#{username},就是接口方法的入参;
  • resultType为"user",这个user是一个别名,具体对应com.nicchagil.mybatisonly.bean.User这个类,我们可以看到在mybatis-config.xml文件的typeAliases节点中已经注册它们的映射关系。
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="com.nicchagil.mybatisonly.mapper.UserMapper">

<select id="queryUser" resultType="user">
select * from t_user_test_1407 t where t.username = #{username}
</select>

<insert id="insertUser" parameterType="user">
INSERT INTO t_user_test_1407 T (T.USERNAME, T.PASSWORD) VALUES (#{username}, #{password})
</insert>

</mapper>

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nicchagil.mybatisonly.mapper.UserMapper"><select id="queryUser" resultType="user">select * from t_user_test_1407 t where t.username = #{username}</select><insert id="insertUser" parameterType="user">INSERT INTO t_user_test_1407 T (T.USERNAME, T.PASSWORD) VALUES (#{username}, #{password})</insert></mapper>

而com.nicchagil.mybatisonly.bean.User是实体类,用于装载数据。

User.java

package com.nicchagil.mybatisonly.bean;

public class User {

private String username;
private String password;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((password == null) ? 0 : password.hashCode());
result = prime * result
+ ((username == null) ? 0 : username.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
}

}

User.java

 1 package com.nicchagil.mybatisonly.bean;2 3 public class User {4 5     private String username;6     private String password;7 8     public String getUsername() {9         return username;
10     }
11
12     public void setUsername(String username) {
13         this.username = username;
14     }
15
16     public String getPassword() {
17         return password;
18     }
19
20     public void setPassword(String password) {
21         this.password = password;
22     }
23
24     @Override
25     public int hashCode() {
26         final int prime = 31;
27         int result = 1;
28         result = prime * result
29                 + ((password == null) ? 0 : password.hashCode());
30         result = prime * result
31                 + ((username == null) ? 0 : username.hashCode());
32         return result;
33     }
34
35     @Override
36     public boolean equals(Object obj) {
37         if (this == obj)
38             return true;
39         if (obj == null)
40             return false;
41         if (getClass() != obj.getClass())
42             return false;
43         User other = (User) obj;
44         if (password == null) {
45             if (other.password != null)
46                 return false;
47         } else if (!password.equals(other.password))
48             return false;
49         if (username == null) {
50             if (other.username != null)
51                 return false;
52         } else if (!username.equals(other.username))
53             return false;
54         return true;
55     }
56
57 }

最后,我们运行Call.java,将能成功查询、插入数据库。我们可通过打印的信息和查询数据库,以查看是否成功查询、插入数据。

3)事务说明

对于数据库有写操作的应用程序,一般来说,事务是不可或缺的一部分。因为未使用其他框架,这里使用编程式事务,即使用SqlSession.commit()和SqlSession.rollback()方法,可见Call.java。

  • 由于本程序对事务有异常回滚的要求,所以,需要获取非自动提交的SqlSession
  • 如程序执行正常,则最后执行session.commit()以提交事务。
    • session.commit()有个需注意的地方,参考其如下注释,即如果当前会话中不涉及updates/deletes/insert等写数动作则不提交事务。所以,如果要触发Mybatis提交事务,就需执行明确的触发动作,如“执行session.insert(...)方法”或“执行对应的SQL Mapper配置中的insert、update、delete等标签”等操作。(本人曾尝试在SQL Mapper配置中用select标签包含INSERT的SQL,使用SqlSession.commit()后,执行正常,但没有提交事务,可见并未触发,所以,需规范使用标签)。如需强制提交,可用SqlSession.commit(boolean)。

      Flushes batch statements and commits database connection. Note that database connection will not be committed if no updates/deletes/inserts were called. To force the commit call SqlSession.commit(boolean)

  • 如程序执行异常,则回滚事务,session.rollback()

单独搭建Mybaits完毕!

二、 Mybatis与Spring的整合

一个项目中,单独使用Mybatis的情况并不多;更多的情况下,我们需要将Mybatis与其他框架进行整合,以便更好地使用。比如Mybatis + Spring,就是一个流行的整合组合。

1)环境准备、版本说明

本次用Mybatis3 + Spring3进行整合。注意,并不包含MVC框架的配置,因为本文的目的是学习Mybatis,所以尽量不引用其他框架,以避免影响代码的理解。

需引入的类库详情如下:

MVN dependencies

<dependencies>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-webflow</artifactId>
<version>2.4.0.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-oracle</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.4</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>

</dependencies>

<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>3.2.10.RELEASE</version></dependency><dependency><groupId>org.springframework.webflow</groupId><artifactId>spring-webflow</artifactId><version>2.4.0.RELEASE</version></dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-oracle</artifactId><version>1.0.0.RELEASE</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.2.4</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.2.2</version></dependency></dependencies>

2)程序的搭建

首先,我们在Spring中配置关于Mybatis数据源的信息。

这里以applicationContext-mybatis.xml来体现,配置了如下信息:

  • 注册数据源,常见的有JDBC或JNDI,根据具体情况择一。
  • 注册sqlSessionFactory
  • 在哪些package下扫描Mapper接口,即DAO接口
applicationContext-mybatis.xml

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

<!-- JDBC Data Source -->
<!--
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url"
value="jdbc:oracle:thin:@hostname:port:sid" />
<property name="username" value="username" />
<property name="password" value="password" />
</bean>
-->

<!-- JNDI Data Source -->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>JNDI_TEST_DB</value>
</property>
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations">
<list>
<value>classpath:com/nicchagil/mybatis3spring3intg/mapper/sqlxml/*_mapper.xml</value>
<value>classpath:com/nicchagil/mybatis3spring3intg/bean/resultmapxml/*_resultmap.xml</value>
</list>
</property>
<property name="typeAliasesPackage" value="com.nicchagil.mybatis3spring3intg.bean" />
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.nicchagil.mybatis3spring3intg.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>

</beans>

applicationContext-mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><!-- JDBC Data Source --><!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" ><property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /><property name="url"value="jdbc:oracle:thin:@hostname:port:sid" /><property name="username" value="username" /><property name="password" value="password" /></bean>--><!-- JNDI Data Source --><bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"><property name="jndiName"><value>JNDI_TEST_DB</value></property></bean><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="mapperLocations"><list><value>classpath:com/nicchagil/mybatis3spring3intg/mapper/sqlxml/*_mapper.xml</value><value>classpath:com/nicchagil/mybatis3spring3intg/bean/resultmapxml/*_resultmap.xml</value></list></property><property name="typeAliasesPackage" value="com.nicchagil.mybatis3spring3intg.bean" /></bean><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.nicchagil.mybatis3spring3intg.mapper" /><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /></bean></beans>

除了Mybatis的信息,还有一些Spring的信息需要配置:

  • 根据注解自动扫描并注册bean
  • Spring的声明式事务管理(用以替代上一章节的“编程式事务”)
  • 由于本程序没有集成MVC框架,在Servlet是通过Spring编程式地获得Spring管理的bean,所以这里注册一个Spring的工具类。(使用了MVC框架并将框架交由Spring IOC容器管理的,可忽视此点配置)
applicationContext.xml

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

<context:component-scan base-package="com.nicchagil.mybatis3spring3intg" />

<!-- Transaction Support -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

<bean id="SpringContextUtil" class="com.nicchagil.util.SpringContextUtil"/>

</beans>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"><context:component-scan base-package="com.nicchagil.mybatis3spring3intg" /><!-- Transaction Support --><tx:annotation-driven transaction-manager="transactionManager" /><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><bean id="SpringContextUtil" class="com.nicchagil.util.SpringContextUtil"/></beans>

众所周知,以上是Spring的配置文件,那么我们需要告诉应用程序“这些配置文件在哪里”,所以我们需要在web.xml中告诉应用程序。另外,此web.xml注册了一个Servlet,用于接收页面的请求。

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>mybatis3spring3Intg</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config/applicationContext*.xml</param-value>
</context-param>
<servlet>
<description></description>
<display-name>UserServlet</display-name>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.nicchagil.mybatis3spring3intg.servlet.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/UserServlet</url-pattern>
</servlet-mapping>
</web-app>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"><display-name>mybatis3spring3Intg</display-name><welcome-file-list><welcome-file>index.html</welcome-file></welcome-file-list><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><context-param><param-name>contextConfigLocation</param-name><param-value>classpath*:config/applicationContext*.xml</param-value></context-param><servlet><description></description><display-name>UserServlet</display-name><servlet-name>UserServlet</servlet-name><servlet-class>com.nicchagil.mybatis3spring3intg.servlet.UserServlet</servlet-class></servlet><servlet-mapping><servlet-name>UserServlet</servlet-name><url-pattern>/UserServlet</url-pattern></servlet-mapping>
</web-app>

我们还需要定义Mapper的接口,即DAO接口。此处的Mapper的接口,我们已经在applicationContext-mybatis.xml中注册为指定路径下自动扫描。

UserMapper.java

package com.nicchagil.mybatis3spring3intg.mapper;

import com.nicchagil.mybatis3spring3intg.bean.User;

public interface UserMapper {

public User find(String username);

public void save(User user);

}

UserMapper.java

package com.nicchagil.mybatis3spring3intg.mapper;import com.nicchagil.mybatis3spring3intg.bean.User;public interface UserMapper {public User find(String username);public void save(User user);}

而Mapper的实现是如何的呢?

Mybatis会帮我们实现,我们只需要通过user_mapper.xml文件告诉Mybatis对应的SQL,此处的mapper文件,已经在applicationContext-mybatis.xml中注册为指定路径下自动扫描。

user_mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nicchagil.mybatis3spring3intg.mapper.UserMapper"><select id="find" resultType="user" resultMap="userResultMap">select * from t_user_test_1407 t where t.username = #{username}</select><insert id="save" parameterType="user">INSERT INTO t_user_test_1407 T (T.USERNAME, T.PASSWORD) VALUES (#{username}, #{password})</insert></mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nicchagil.mybatis3spring3intg.mapper.UserMapper"><select id="find" resultType="user" resultMap="userResultMap">select * from t_user_test_1407 t where t.username = #{username}</select><insert id="save" parameterType="user">INSERT INTO t_user_test_1407 T (T.USERNAME, T.PASSWORD) VALUES (#{username}, #{password})</insert></mapper>

可以看到,Mapper和SQL配置文件中都引用到了实体类,我们也需要定义。此处的实体类,已经在applicationContext-mybatis.xml中注册为指定路径下自动扫描。

User.java

package com.nicchagil.mybatis3spring3intg.bean;

public class User {

private String username;
private String password;
private String childhoodName;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public String getChildhoodName() {
return childhoodName;
}

public void setChildhoodName(String childhoodName) {
this.childhoodName = childhoodName;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((childhoodName == null) ? 0 : childhoodName.hashCode());
result = prime * result
+ ((password == null) ? 0 : password.hashCode());
result = prime * result
+ ((username == null) ? 0 : username.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (childhoodName == null) {
if (other.childhoodName != null)
return false;
} else if (!childhoodName.equals(other.childhoodName))
return false;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
}

}

User.java

package com.nicchagil.mybatis3spring3intg.bean;public class User {private String username;private String password;private String childhoodName;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getChildhoodName() {return childhoodName;}public void setChildhoodName(String childhoodName) {this.childhoodName = childhoodName;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result+ ((childhoodName == null) ? 0 : childhoodName.hashCode());result = prime * result+ ((password == null) ? 0 : password.hashCode());result = prime * result+ ((username == null) ? 0 : username.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;User other = (User) obj;if (childhoodName == null) {if (other.childhoodName != null)return false;} else if (!childhoodName.equals(other.childhoodName))return false;if (password == null) {if (other.password != null)return false;} else if (!password.equals(other.password))return false;if (username == null) {if (other.username != null)return false;} else if (!username.equals(other.username))return false;return true;}}

实体的属性与DB的字段之间的映射/匹配,我们需要定义一下。此处的resultmap.xml文件已经在applicationContext-mybatis.xml中注册为指定路径下自动扫描。

user_resultmap.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="com.nicchagil.mybatis3spring3intg.mapper.UserMapper">
<resultMap type="user" id="userResultMap">
<result property="username" column="USERNAME" />
<result property="password" column="PASSWORD" />
<result property="childhoodName" column="USERNAME" />
</resultMap>
</mapper>

user_resultmap.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="com.nicchagil.mybatis3spring3intg.mapper.UserMapper"><resultMap type="user" id="userResultMap"><result property="username" column="USERNAME" /><result property="password" column="PASSWORD" /><result property="childhoodName" column="USERNAME" /></resultMap>
</mapper>

完成了DAO,那么接着写Service。

首先一个Service的接口。

UserService.java

package com.nicchagil.mybatis3spring3intg.service;

import com.nicchagil.mybatis3spring3intg.bean.User;

public interface UserService {

public User query(String username);

public void save(User user);

public void testTransaction(User user1, User user2);

}

UserService.java

package com.nicchagil.mybatis3spring3intg.service;import com.nicchagil.mybatis3spring3intg.bean.User;public interface UserService {public User query(String username);public void save(User user);public void testTransaction(User user1, User user2);}

Service的实现类如下,这里只简单地测试查询、保存、事务是否能正常处理。

UserServiceImpl.java

package com.nicchagil.mybatis3spring3intg.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.nicchagil.mybatis3spring3intg.bean.User;
import com.nicchagil.mybatis3spring3intg.mapper.UserMapper;
import com.nicchagil.mybatis3spring3intg.service.UserService;

@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserMapper mapper;

@Override
public User query(String username) {
return mapper.find(username);
}

@Override
public void save(User user) {
mapper.save(user);
}

@Override
@Transactional
public void testTransaction(User user1, User user2) {
mapper.save(user1);

// Code a NullPointerException to test transaction setting
String str = null;
str.charAt(0);

mapper.save(user2);
}

}

UserServiceImpl.java

由于没有整合MVC框架,此处由一个Servlet(此Servlet已于web.xml中注册)获取页面请求并调用Service,

那么如何在Servlet中获得Spring IOC管理下Service的bean呢?这里借助SpringContextUtil(implements ApplicationContextAware),此SpringContextUtil于以上提及的applicationContext.xml中注册。

UserServlet.java

package com.nicchagil.mybatis3spring3intg.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.nicchagil.mybatis3spring3intg.bean.User;
import com.nicchagil.mybatis3spring3intg.service.UserService;
import com.nicchagil.util.SpringContextUtil;

/**
* Servlet implementation class UserServlet
*/
public class UserServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

/**
* @see HttpServlet#HttpServlet()
*/
public UserServlet() {
super();
// TODO Auto-generated constructor stub
}

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}

/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String action = request.getParameter("action");

UserService service = (UserService)SpringContextUtil.getBean("userServiceImpl");

if ("find".equals(action)) {
User user = service.query(request.getParameter("username"));
System.out.println(user.getUsername() + " - " + user.getPassword() + " - " + user.getChildhoodName());

}

if ("save".equals(action)) {
User user = new User();
user.setUsername(request.getParameter("username"));
user.setPassword(request.getParameter("password"));

service.save(user);
System.out.println(user.getUsername() + " - " + user.getPassword());

}

if ("testTransaction".equals(action)) {
User user1 = new User();
user1.setUsername(request.getParameter("username"));
user1.setPassword(request.getParameter("password"));

User user2 = new User();
user2.setUsername(request.getParameter("username") + " - Double");
user2.setPassword(request.getParameter("password") + " - Double");

service.testTransaction(user1, user2);
System.out.println(user1.getUsername() + " - " + user1.getPassword());
System.out.println(user2.getUsername() + " - " + user2.getPassword());

}

}

}

UserServlet.java

package com.nicchagil.mybatis3spring3intg.servlet;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import com.nicchagil.mybatis3spring3intg.bean.User;
import com.nicchagil.mybatis3spring3intg.service.UserService;
import com.nicchagil.util.SpringContextUtil;/*** Servlet implementation class UserServlet*/
public class UserServlet extends HttpServlet {private static final long serialVersionUID = 1L;/*** @see HttpServlet#HttpServlet()*/public UserServlet() {super();// TODO Auto-generated constructor stub}/*** @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)*/protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}/*** @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)*/protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String action = request.getParameter("action");UserService service = (UserService)SpringContextUtil.getBean("userServiceImpl");if ("find".equals(action)) {User user = service.query(request.getParameter("username"));System.out.println(user.getUsername() + " - " + user.getPassword() + " - " + user.getChildhoodName());}if ("save".equals(action)) {User user = new User();user.setUsername(request.getParameter("username"));user.setPassword(request.getParameter("password"));service.save(user);System.out.println(user.getUsername() + " - " + user.getPassword());}if ("testTransaction".equals(action)) {User user1 = new User();user1.setUsername(request.getParameter("username"));user1.setPassword(request.getParameter("password"));User user2 = new User();user2.setUsername(request.getParameter("username") + " - Double");user2.setPassword(request.getParameter("password") + " - Double");service.testTransaction(user1, user2);System.out.println(user1.getUsername() + " - " + user1.getPassword());System.out.println(user2.getUsername() + " - " + user2.getPassword());}}}

SpringContextUtil.java

package com.nicchagil.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class SpringContextUtil implements ApplicationContextAware {

private static ApplicationContext applicationContext = null;

@Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
applicationContext = ac;

}

public static ApplicationContext getApplicationContext() {
return applicationContext;
}

public static Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}

public static boolean containsBean(String beanName) {
return applicationContext.containsBean(beanName);
}

}

SpringContextUtil.java

package com.nicchagil.util;import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;public class SpringContextUtil implements ApplicationContextAware {private static ApplicationContext applicationContext = null;@Overridepublic void setApplicationContext(ApplicationContext ac)throws BeansException {applicationContext = ac;}public static ApplicationContext getApplicationContext() {return applicationContext;}public static Object getBean(String beanName) {return applicationContext.getBean(beanName);}public static boolean containsBean(String beanName) {return applicationContext.containsBean(beanName);}}

几乎大功告成。

这里写了些触发测试的页面,执行结果可通过“查看控制台”或“查询数据库”获得。哈哈!~~

导航页

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

<a href="find.html">find</a>
<br/>
<a href="save.html">save</a>
<br/>
<a href="testTransaction.html">testTransaction</a>

</body>
</html>

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body><a href="find.html">find</a>
<br/>
<a href="save.html">save</a>
<br/>
<a href="testTransaction.html">testTransaction</a></body>
</html>

输入username查询记录的触发页面

find.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

<form action="UserServlet">
<input type="hidden" name="action" value="find">
<input type="text" name="username">
<input type="submit">
</form>

</body>
</html>

find.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body><form action="UserServlet"><input type="hidden" name="action" value="find"><input type="text" name="username"><input type="submit"></form></body>
</html>

保存页面

save.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<body>

<form action="UserServlet">
<input type="hidden" name="action" value="save">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit">
</form>

</body>

</body>
</html>

save.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<body><form action="UserServlet"><input type="hidden" name="action" value="save"><input type="text" name="username"> <input type="password" name="password"> <input type="submit"></form></body></body>
</html>

测试事务的触发页面

testTransaction.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<body>

<form action="UserServlet">
<input type="hidden" name="action" value="testTransaction">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit">
</form>

</body>

</body>
</html>

testTransaction.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<body><form action="UserServlet"><input type="hidden" name="action" value="testTransaction"><input type="text" name="username"> <input type="password" name="password"> <input type="submit"></form></body></body>
</html>

大功告成!!

分享于:

https://github.com/nicchagil/mybatis3spring3Intg/tree/mybatis3spring3Intg_branch_initialization

转载于:https://www.cnblogs.com/telwanggs/p/5403165.html

由“单独搭建Mybatis”到“Mybatis与Spring的整合/集成”相关推荐

  1. Spring Boot 教程(三): Spring Boot 整合Mybatis

    教程简介 本项目内容为Spring Boot教程样例.目的是通过学习本系列教程,读者可以从0到1掌握spring boot的知识,并且可以运用到项目中.如您觉得该项目对您有用,欢迎点击收藏和点赞按钮, ...

  2. Spring Boot整合Jpa多数据源

    Spring Boot整合Jpa多数据源 本文是Spring Boot整合数据持久化方案的最后一篇,主要和大伙来聊聊Spring Boot整合Jpa多数据源问题.在Spring Boot整合JbdcT ...

  3. mybatis的环境搭建及如何和搭配spring使用

    本次博客主要介绍mybatis的环境搭建及如何和搭配spring使用,关于动态sql的部分可能会放在后面找一个专题来写.建议要有一定的ibatis的基础 1maven组织结构所需要的jar包 01 & ...

  4. Java框架搭建-Maven、Mybatis、Spring MVC整合搭建

    Java框架搭建-Maven.Mybatis.Spring MVC整合搭建 1. 下载eclipse 到网站下载 http://www.eclipse.org/downloads/packages/e ...

  5. 史上最细IDEA搭建基于SSM(springmvc+spring+mybatis)

    需要准备的环境: idea 2019.3.2 jdk1.8 Maven 3.3.9 请提前将idea与Maven.jdk配置好,本次项目用的都是比较新的 注:配置完ide红线报错没关系!可以run! ...

  6. java搭建o2o平台_java版 spring cloud+mybatis 构建 b2b2c o2o 多租户电子商务平台

    用java实施的电子商务平台太少了,使用spring cloud技术构建的b2b2c电子商务平台更少,大型企业分布式互联网电子商务平台,推出PC+微信+APP+云服务的云商平台系统,其中包括B2B.B ...

  7. IDEA搭建简单的SSM(spring+springMVC+mybatis)框架

    一直想自己搭个后台框架来玩玩,只是惰性这个东西往往占据了上风,值此新春佳节,风和日丽,艳阳高照之际,就开始自己的博客之旅吧. 首先先来了解一下SSM这三个东西! (1)spring:是一个轻量级的ja ...

  8. 简单的利用IDEA搭建SpringBoot+Maven+Mybatis+自动生成代码

    最近在系统的学习SpringBoot框架,并且要用该框架做个项目--网上也大大小小看了很多教程,感觉很多写文章的人都不太负责任,只知道搬运,大概都没有实际操作过,问题也是有很多,所以自己写一篇文章记录 ...

  9. 2021最新Java面试题(Hibernate面试题、MyBatis面试题、Spring面试题、SpringMVC面试题)

    1.什么是 ORM 框架? 答:对象-关系映射(Object-Relational Mapping,简称ORM),面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境 ...

最新文章

  1. 小学一年级计算机社团计划,一年级社团活动计划.doc
  2. Windows系统笔记本禁用自带键盘
  3. 2. 两数相加(中等)
  4. 在 vue 组件中查看 vuex 定义
  5. 在 CentOS 上安装和配置 Xen 虚拟化
  6. poj 1068 Parencodings
  7. adb命令查看手机电量_desired Capabilities和aapt命令查看手机包信息
  8. android常用开源库分享
  9. 我的游戏学习日志17——游戏元素的解析(1)
  10. 关于jacob 无法创建ActiveXCompnent对象的几种可能性
  11. 基于机器视觉的细小金属件表面污渍检测
  12. 无根树的同构:Hash最小表示法(bzoj 4337: BJOI2015 树的同构)
  13. 卡诺模型案例分析_设计师必修课:KANO 模型的讲解与案例分析
  14. Python下载视频
  15. pod健康检查详解(liveness,readiness,滚动更新)
  16. hive执行insert overwrite失败,报错 could notbe cleaned up错误
  17. unity android录制视频教程,Unity移动端视频录制,Android和IOS都支持
  18. python制作地图
  19. 华芯微特SWM181学习笔记--GPIO应用与环境搭建
  20. 虚拟机云服务器6.0教程pdf,虚拟机云服务器6.0教程pdf

热门文章

  1. mysql 同步 有log_MySQL之主从同步
  2. Python 语法糖
  3. 关于EXCEL相关类的一些函数解释
  4. 2020.xilinx开发环境
  5. 1014.修改clion的工具链
  6. lwip-1.4.1文档rawapi中文翻译
  7. 【其他】文件头注释、函数头注释、全局变量注释规范
  8. 数据结构之图的存储结构二及其实现
  9. MPICH C语言接口函数说明
  10. (2)散列表是怎么进行查找的