1. mybatis中的连接池以及事务控制原理部分了解
1)mybatis中连接池使用及分析;
2)mybatis事务控制的分析
2. mybatis基于XML配置的动态SQL语句使用
1)mappers配置文件中的几个标签:、、 、
3. mybatis中的多表操作
1) 一对多
2) 一对一
3) 多对多
1、Mybatis 连接池与事务深入
1.1 连接池
连接池:我们在实际开发中都会使用连接池。因为它可以减少我们获取连接所消耗的时间。
mybatis连接池提供了3种方式的配置,配置的位置是主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式。
type属性的取值:
POOLED:采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现;
UNPOOLED:采用传统的获取连接的方式,虽然也实现javax.sql.DataSource接口,但是并没有使用池的思想,因此每次使用都会重新获取连接。
JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。注意:如果不是web或者maven的war工程,是不能使用的。我们课程中使用的是tomcat服务器,采用连接池就是dbcp连接池。
MyBatis 内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource,
PooledDataSource 类来表示 UNPOOLED、 POOLED 类型的数据源。MyBatis 在初始化时, 根据的 type 属性来创建相应类型的的数据源 DataSource,即:
type="POOLED": MyBatis 会创建 PooledDataSource 实例
type="UNPOOLED" : MyBatis 会创建 UnpooledDataSource 实例
type="JNDI": MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
MyBatis 是 通 过 工 厂 模 式 来 创 建 数 据 源 DataSource 对 象 的 , MyBatis 定 义了抽象的工厂接口:org.apache.ibatis.datasource.DataSourceFactory,通过其 getDataSource()方法返回数据源DataSource。(具体分析过程见文档——1.1.3 Mybatis 中 DataSource 的存取)
Mybatis 中连接的获取过程分析(文档—1.1.4 Mybatis 中连接的获取过程分析,视频4,5。这部分比较重要,注意原理以及源码的分析!)
设置POOLED属性时的源码分析:
其实连接池分为空闲池以及活动池,线程会先从空闲池中获取,如果空闲池没有连接,会再去活动池中获取,如果活动池中连接的数量小于我们设置的最大数量,会创建一个新的连接放到活动池,这样线程就可以获取新的连接。如果活动池中连接的数量等于我们设置的最大数量,就会获取最老的那个连接,判断这个最老的连接是否失效,失效了就对他进行一定的设置,然后返回给线程使用。(失效就是前面使用这个连接的线程已经不再使用)
MYbatis不使用C3P0或者DBCP等连接池技术,而是使用DataSource接口,自己实现了连接池技术。
当我们需要创建 SqlSession 对象并需要执行 SQL 语句时,这时候 MyBatis 才会去调用 dataSource 对象来创建java.sql.Connection对象。也就是说, java.sql.Connection对象的创建一直延迟到执行SQL语句的时候。
1.2 事务
参考文档——1.2 Mybatis 的事务控制
关于事务,我们需要注意的是:什么是事务,事务的四大特性ACID,不考虑隔离性会产生的3个问题,解决办法:四种隔离级别。(这些是在面试中需要注意的!)
事务:是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作; 这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元)。
参考文章:添加链接描述
mybatis中的事务是通过sqlsession对象的commit方法和rollback方法实现事务的提交和回滚。我们每次执行方法的时候,都会取消自动提交,导致我们每次执行数据库DML操作的时候,都需要手动提交事务,我们可以在获取sqlSession对象的时候,设置可以自动提交:
sqlSession = factory.openSession(true);
当然,只有在每次只执行一个数据库的DML操作的时候,才可以自动提交,如果我们的事务有多个DML操作,设置自动提交,每一个DML语句都会自动提交执行,这样事务就无法控制。一般都会手动提交事务。
2、Mybatis中的动态SQL语句
2.1 if标签与where标签
我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id 查询,如果 username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。(具体见代码–mybatis_day03_dynamicSQL,文档以及视频的解析)
2.2 foreach标签与sql标签
需求
传入多个 id 查询用户信息,用下边两个 sql 实现:
SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)
SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16)
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。这样我们将如何进行参数的传递?
这里使用到QueryVo包装对象,在QueryVo增加一个存储id属性的List集合属性,并添加getter与setter方法:(具体见代码–mybatis_day03_dynamicSQL,文档以及视频的解析)
private List<Integer> ids;
可以使用sql标签定义使用频次较多的sql语句,后面需要使用的时候进行引入即可。后面使用这条语句的时候,可以使用标签引入。(具体见代码–mybatis_day03_dynamicSQL,文档以及视频的解析)
3、Mybatis的多表关联查询——一对多/多对一
具体来说,表之间的关系有4种:一对多、多对一、一对一、多对多。
//一对多与多对一
用户和订单就是一对多,订单和用户就是多对一。因为一个用户可以下多个订单,多个订单属于同一个用户。
如果拿出每一个订单,他都只能属于一个用户,所以Mybatis就把多对一看成了一对一。既Mybatis认为订单中的其中一个与用户之间是一对一的关系。
mybatis中的多表查询(参考项目:mybatis_day03_one2many):
示例:用户和账户
一个用户可以有多个账户,一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
1、建立两张表:用户表,账户表。让用户表和账户表之间具备一对多的关系,需要使用外键在账户表中添加;
2、建立两个实体类:用户实体类和账户实体类,让用户和账户的实体类能体现出一对多的关系;
3、建立两个配置文件,用户的配置文件账户的配置文件;
4、实现配置:当我们查询用户时,可以同时得到用户下所包含的账户信息;当我们查询账户时,可以同时得到账户的所属用户信息息
这部分具体见代码分析,视频12视频分析 ,及相关文档信息。
需求
查询所有账户信息,关联查询下单用户信息。
注意:
因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如
果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。
account表的一对一操作,比如我们在AccountDao的findAllAccountUser方法中,查询所有账户,并且带有用户名称与地址信息(一个account账户对应一个user用户)。
1、我们在AccountDao中添加一个查询所有账户,并且带有用户名称与地址信息的方法
/**
* 查询所有账户,并且带有用户名称与地址信息
* @return
*/
List<AccountUser> findAllAccountUser();
2、我们发现,直接使用如下代码:
<select id="findAllAccountUser" resultType="account">
SELECT a.* , u.username , u.address FROM USER u,account a WHERE u.id = a.uid;
</select>
findAllAccountUser查询出来的结果是User与Account的信息,Account类是无法封装用户信息的。因此我们创建一个AccountUser类,继承Account,包含了username以及address2个属性,使得AccountDao的findAllAccountUser方法返回的结果是AccountUser类。
3、我们在Account.xml中添加查询标签如下:
<!--查询所有账户,并且带有用户名称与地址信息-->
<select id="findAllAccountUser" resultType="accountuser">
SELECT a.* , u.username , u.address FROM USER u,account a WHERE u.id = a.uid;
</select>
这样,findAllAccountUser方法查询出来的结果包含User的username与address信息,还有account表的所有信息,将这些信息封装到AccountUser的时候,由于AccountUser继承Account,因此account的信息可以封装到AccountUser的父类Account,而User的username与address信息可以封装到AccountUser的username与address属性中。这样,查询出来的Account与User的信息就可以封装到结果!!!
4、接下来我们测试:
@Test
public void testFindAllAccountUser()
{
List<AccountUser> allAccountUser = accountDao.findAllAccountUser();
for (AccountUser accountUser : allAccountUser)
{
System.out.println(accountUser);
}
}
结果是:
1、我们在AccountDao有查询所有账户的方法findAll,同时还要获取到当前账户的所属用户信息。最后查询出来的数据封装到Account类中
List<Account> findAll();
2、我们之前提过,如果要实现多表查询,必须要让用户和账户的实体类能体现出一对多的关系。因此,从表(多,既account表)实体应该包含一个主表(一,user)实体的对象引用。
因此,我们在从表account表对应的实体类Account中,创建主表user的实体类User类的对象引用,并创建getter与setter方法。
private User user;
3、我们在AccountDao.xml中,设置一个查询标签
<select id="findAll" resultType="account">
SELECT u.* , a.id AS aid , a.uid , a.money FROM USER u,account a WHERE u.id = a.uid;
</select>
现在查询出来的结果包含account与user的信息,只能将查询出来的account表的信息封装到Account类的普通属性中,如果我们想让查询出来的对应User的数据封装到Account类的User属性,需要进行resultMap配置。
4、resultMap的配置:
<!-- 定义封装查询出来的 account和user 信息的resultMap -->
<!--
1、前面已经定义 com.lkj.domain 包下的所有实体类按其类名起别名,这里不需要再写 com.lkj.domain.Account ,直接写account,
type="account" 表示要将结果封装到com.lkj.domain.Account类
2、注意,在这个resultMap中,出现了2个id,为了避免冲突,我们给account表的id取一个别名aid。
因为我们是在<id>标签里面设置,我们直接写 column="aid" ,系统会自动将account表的id属性起别名为aid。
如果下面的SQL语句已经给id起别名为aid,那么这里必须强制起别名为aid。如果下面SQL语句没有起别名,那么这里可以取,也可以不取!!!
(只有id可以这样起别名,其他属性都是在<result>标签中设置,不可以这样起别名,而且其他属性一般不会冲突,不需要起别名)
补充:property 是实体类的属性,column 是数据库表的属性
-->
<resultMap id="accountUserMap" type="account">
<!--首先,Account类中配置封装account表查询出来的内容-->
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一对一的关系映射:配置封装user的内容-->
<!--
1、使用<association>标签来将user表中查询出来的数据封装到Account类的user属性中。
2、property="user" 表示查询出来的user表的信息封装到Account对象的user属性
3、column="uid",表示user表的信息要通过account表的uid对应查询
column="uid" , 表示通过account表的 uid 属性(外键),可以确定uid对应user表中id,既可以确定user表查询出来的内容。
这样我们就可以知道查询出来的账户信息所对应的用户信息。(这里的column一般是从表的外键属性)
这里也可以理解为,我们要将查询出来的user表的信息封装到Account类的user属性,首先要通过account表的uid属性来查询user表的信息。
4、javaType属性:表示Account类中user属性的类型
我们这里将查询出来的account表的信息的uid对应的user表的信息封装到com.lkj.domain.User类,
前面已经定义 com.lkj.domain 包下的所有实体类按其类名起别名,这里不需要再写 com.lkj.domain.User ,直接写user
-->
<association property="user" column="uid" javaType="user">
<!--里面写User类属性与user表属性的对应-->
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
5、查询的标签定义为:
<!-- 查询所有账户,并且带有用户名称与地址信息 -->
<!--
我们将返回的结果设置为 resultMap="accountUserMap"
-->
<select id="findAll" resultMap="accountUserMap">
SELECT u.* , a.id AS aid , a.uid , a.money FROM USER u,account a WHERE u.id = a.uid;
</select>
6、测试:
/**
* 查询所有账户account,并且带有用户名称与地址信息
*/
@Test
public void testFindAll()
{
List<Account> accountList = accountDao.findAll();
for (Account account : accountList)
{
System.out.println("--------每个account的信息------------");
System.out.println(account);//只会打印Account类原有的属性,因为Account的toString只打印了它原有的属性
/*
我们查询出来的user表的信息封装到了Account类的user属性,因此我们这里需要打印Account类的user属性,
这样才会打印查询出来的user表的信息。
*/
System.out.println(account.getUser());//打印出查询出来的user表的信息
}
}
需求:
查询所有用户信息及用户关联的账户信息。
分析:
用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息
查询出来,我们想到了左外连接查询比较合适。(账户一定有对应的用户,但是用户不一定有对应的账户)如果不使用左外连接,那些没有账户信息的用户信息就无法查询出来。
user表的一对多操作,比如我们在UserDao的findAll方法中,查询所有用户,并且获取该用户下的所有账户信息(一个user用户对应一个/多个/0个account账户,)。
1、在UserDao下有一个方法:
//查询所有用户,同时获取该用户下的所有账户信息
List<User> findAll();
2、我们想通过主表查询到对应从表的信息(一对多关系映射),此时主表实体应该包含从表实体的集合引用
private List<Account> account;//注意生成getter与setter
注意区别于从表到主表查询的一对一,一对一从表实体应该包含一个主表实体的对象引用。(因为User可能对应多个Account,而Account只能对应一个User)
3、resultMap的设置:
<!--同样,先定义封装查询出来的user(一)和account(多)信息的resultMap-->
<!--
1、查询出来的信息封装到com.lkj.domain.User中,已经起别名,使用user表示
-->
<resultMap id="userAccountMap" type="user">
<!--首先是配置User对象原有属性的映射。信息从user表查询-->
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!--其次,配置User对象中accounts集合的映射。信息从account表查询-->
<!--
1、这里一对多使用的是 collection 标签,一对一使用的是<association>标签
2、property="accounts" 表示查询出来的account表的信息封装到User对象的accounts属性
3、ofType="account" 表示User类中accounts集合中元素的类型(前面SqlMapConfig.xml已经取别名,否则使用全限定类名)
4、前面在Account类中查询user属性,需要指定 column="uid" ,既通过account表的 uid 属性去查询user表,才能查询出账户对应的用户信息
但是在这里,我们在User类中查询accounts属性,则不需要指定通过user表的哪一个属性可以查询account表的信息
注意区分,主表对从表查询(一对多)配置resultMap的collection的时候不需要指定 column
-->
<collection property="accounts" ofType="account">
<!--
1、注意,在这个resultMap中,出现了2个id,为了避免冲突,我们给account表的id取一个别名aid。
因为我们是在<id>标签里面设置,我们直接写 column="aid" ,系统会自动将account表的id属性其别名为aid。
(只有id可以这样起别名,其他属性都是在<result>标签中设置,不可以这样起别名,,而且其他属性一般不会冲突,不需要起别名)
补充:property 是实体类的属性,column 是数据库表的属性
-->
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
4、 查询用户信息的标签如下:
<!-- 询所有用户,同时获取该用户下的所有账户信息 -->
<!--
1、这里需要查询所有用户的信息,不管有没有账户信息,用户信息都得有。
但是想之前那样使用隐式内连接查询,没有账户的用户信息查询不到,因此使用左外链接
-->
<select id="findAll" resultMap="userAccountMap">
select * from user u left outer join account a on u.id = a.uid
</select>
5、测试
/**
* 查询所有用户,同时获取该用户下的所有账户信息
*/
@Test
public void testFindAll()
{
List<User> list = userDao.findAll();
for (User user : list)
{
System.out.println("------每个用户信息------");
System.out.println(user);
System.out.println(user.getAccounts());
}
//结果,发现所有的用户信息都打印出来,包括有账户信息以及没有账户信息的
// 对于重复的用户信息(因为一个用户有2个账户,出现对应2个账户的2个用户),mybatis会自动识别并将所有账户信息封装到一个用户中
}
注意:
collection:部分定义了用户关联的账户信息。表示关联查询结果集。
property="accounts":关联查询的结果集存储在 User 对象的上哪个属性。
ofType="account":指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。
4、Mybatis 多表查询之多对多
示例:用户和角色
一个用户可以有多个角色, 一个角色可以赋予多个用户
步骤:
1、建立两张表:用户表,角色表:让用户表和角色表具有多对多的关系。需要使用中间表,中间表中包含各自的主键,在中间表中是外键。
2、建立两个实体类:用户实体类和角色实体类。让用户和角色的实体类能体现出来多对多的关系——各自包含对方一个集合引用。
3、建立两个配置文件:用户的配置文件角色的配置文件。
4、实现配置:当我们查询用户时,可以同时得到用户所包含的角色信息;当我们查询角色时,可以同时得到角色的所赋予的用户信息。
准备工作见视频15、16分析(项目:mybatis_day03_many2many)
准备
1)创建3张表并插入数据:用户表user、角色表role、中间表user_role。3张表之间的关系如下图。
2)创建role表的实体类(属性名与role表的属性名不相同),同时创建role的DAO接口:RoleDao,既其相应的xml文件RoleDao.xml。
由于我们在SqlMapConfig.xml中使用 <package name="com.lkj.dao"></package> 配置所有 com.lkj.dao 包下面的dao.xml文件的映射,因此这里不需要再在SqlMapConfig.xml中导入RoleDao.xml。
1、在Role的实体类中,创建多对多的关系映射,既一个角色可以赋予多个用户。我们在Role中创建一个返回User类型集合的users属性。
private List<User> users;
2、RoleDao中的查询所有角色以及角色所属用户信息的方法为:
/**
* 查询所有角色,获取角色下所属用户信息
* @return
*/
List<Role> findAll();
3、查询的SQL语句的分析(见视频15分析,这部分是难点)
我们查询的时候,不仅要将角色信息全部查询出来,还要将角色对应的用户信息查询出来(不管角色有没有对应的用户,角色全部要显示)。此时应该利用中间表user_role。
首先,我们使用左外连接,先依据 role.id = user_role.rid ,将满足条件的role表中的信息全部查询出来。语句如下,查询出来的信息如下图1:
SELECT * FROM role r LEFT OUTER JOIN user_role ur ON r.id = ur.rid;
查询出来的是一个新的表。随后,我们根据新表中的所有uid对应user表的id,再去左外查询user表。语句如下,查询出来的信息如下图2:
SELECT u.* , r.id AS rid , r.role_name , r.role_desc FROM
role r LEFT OUTER JOIN user_role ur ON r.id = ur.rid
LEFT OUTER JOIN USER u ON u.id = ur.rid;
此处结果含有多个id,为了区分,我们将role表的id命名为rid。这样,查询出来的表就包含所有role表的信息以及role表中角色对应的用户的信息(没有对应用户信息的角色也查询出来)
当然语句也可以写为下面的形式:
SELECT u.* , r_ur.id AS rid , r_ur.role_name , r_ur.role_desc FROM
(SELECT * FROM role r LEFT OUTER JOIN user_role ur ON r.id = ur.rid) r_ur
LEFT OUTER JOIN USER u ON u.id = r_ur.uid;
我们将第一次查询出来的信息命名为一个新的表r_ur,这个新的表再与user表进行左外连接的查询,我们获取user表的全部以及r_ur表的 id、role_name、role_desc 信息即可,中间表的信息不需要。(这种方法是比较容易理解的! )
4、resultMap的配置
<!--定义role表的resultMap-->
<!--
1、Windows系统下mysql不区分大小写,可以直接写role_desc,而不必写ROLE_DESC
2、为了避免结果id重复,将role表的id命名为rid
-->
<resultMap id="roleMap" type="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<!--其次,配置Role对象中users集合的映射。信息从user表查询-->
<!--
1、同样,一对多使用<collection>标签;
2、property="users" 表示查询出来的user表的信息封装到Role对象的users属性
3、ofType="user" 表示Role类中users集合中元素的类型为com.lkj.domain.user(前面SqlMapConfig.xml已经取别名,否则使用全限定类名)
-->
<collection property="users" ofType="user">
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</collection>
</resultMap>
5、查询语句
<!--查询所有角色,获取角色下所属用户信息-->
<select id="findAll" resultMap="roleMap">
SELECT u.* , r.id AS rid , r.role_name , r.role_desc FROM
role r LEFT OUTER JOIN user_role ur ON r.id = ur.rid
LEFT OUTER JOIN USER u ON u.id = ur.uid;
</select>
6、测试
/**
* 查询所有
*/
@Test
public void testFindAll()
{
List<Role> list = roleDao.findAll();
for (Role role : list)
{
System.out.println("------每个角色信息------");
System.out.println(role);
System.out.println(role.getUsers());
}
}
1、查询所有用户以及用户所对应的角色信息,没有对应角色的用户信息也要查询出来。
2、SQL语句
其实把刚才的SQL语句的角色与用户调转一下即可,既先使用用户与user_role表进行查询,查询出来的表再与role表进行查询
SELECT u.* , r.id AS rid , r.role_name , r.role_desc FROM
USER u LEFT OUTER JOIN user_role ur ON u.id = ur.uid
LEFT OUTER JOIN role r ON r.id = ur.rid;
或者
SELECT u_ur.id , u_ur.username , u_ur.birthday, u_ur.sex , u_ur.address,
r.id AS rid , r.role_name , r.role_desc FROM
(SELECT * FROM USER u LEFT OUTER JOIN user_role ur ON u.id = ur.uid) u_ur
LEFT OUTER JOIN role r ON r.id = u_ur.rid; -- 起别名只在最后查询结果起作用,这里还是要使用r.id,而不是r.rid
3、同样,在User的实体类中,创建多对多的关系映射,既一个用户可以有多个角色。我们在User中创建一个返回Role类型集合的roles属性。
private List<Role> roles;
4、resultMap
<resultMap id="userMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!--配置角色集合的映射-->
<collection property="roles" ofType="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
</collection>
</resultMap>
5、查询语句
<!-- 查询所有用户以及用户包含的角色信息-->
<select id="findAll" resultMap="userMap">
SELECT u.* , r.id AS rid , r.role_name , r.role_desc FROM
USER u LEFT OUTER JOIN user_role ur ON u.id = ur.uid
LEFT OUTER JOIN role r ON r.id = ur.rid;
</select>
6、测试
/**
* 查询所有用户,同时获取该用户下的所有账户信息
*/
@Test
public void testFindAll()
{
List<User> list = userDao.findAll();
for (User user : list)
{
System.out.println("------每个用户信息------");
System.out.println(user);
System.out.println(user.getRoles());
5、JNDI补充
这部分见视频17-19,以及资料中的JNDI文档。这部分不是主要内容,只对其中需要注意的部分进行说明。
JNDI:Java Naming and Directory Interface(java命名和目录接口)。是SUN公司推出的一套规范,属于JavaEE技术之一,目的是模仿windows系统中的注册表。在我们这里,JNDI是用来在Tomcat服务器中注册数据源。
下面是JNDI的结构,如下:
1、我们需要创建一个Maven的web工程来演示。(项目mybatis_day03_jndi)
2、需要在webapps下创建一个META-INF,里面放context.xml文件,内容如下,注意将数据库部分修改为我们自己的数据库内容。
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!--
<Resource
name="jdbc/eesy_mybatis" 数据源的名称(可以随便起)
type="javax.sql.DataSource" 数据源类型
auth="Container" 数据源提供者(这里指的是由Tomcat提供)
maxActive="20" 最大活动数
maxWait="10000" 最大等待时间
maxIdle="5" 最大空闲数
username="root" 用户名
password="root" 密码
driverClassName="com.mysql.jdbc.Driver" 驱动类
url="jdbc:mysql://localhost:3306/lkj_mybatis" 连接url字符串
/>
-->
<Resource
name="jdbc/lkj_mybatis"
type="javax.sql.DataSource"
auth="Container"
maxActive="20"
maxWait="10000"
maxIdle="5"
username="root"
password="root"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/lkj_mybatis"
/>
</Context>
3、修改SqlMapConfig.xml文件的内容,其实我们只修改了:
<!-- 配置连接数据库的必备信息 type属性表示是否使用数据源(连接池)-->
<dataSource type="JNDI">
<property name="data_source" value="java:comp/env/jdbc/lkj_mybatis"/>
</dataSource>
我们原来是自己制定数据库连接信息,或者提供jdbcComfig.properties来指定,现在是通过指定data_source 来制定,其中 value="java:comp/env/jdbc/lkj_mybatis" ,“java:comp/env/” 是固定的,而 jdbc/lkj_mybatis 是context.xml中的 name 属性的值。
4、在测试之前,需要给项目添加tomcat服务器,参考之前的黑马旅游网的文章,里面对tomcat服务器的添加做了详细的解析,我们可以使用maven自带的tomcat,也可以使用我们本地的tomcat。(这里使用本地的tomcat)
5、此时我们运行之前测试类MybatisTest中的 testFindAll 方法,发现无法运行,因为我们的测试类没有经过Tomcat服务器,也就是无法使用Tomcat服务器给我们准备的 连接数据库的JNDI的Map数据源(我们这里使用的是JNDI配置),无法连接到数据库,因此无法运行。
此时应该将测试类测试类的内容放到jsp的java代码块区域,由于jsp会经过服务器,这样它里面的java代码就会经过服务器,就可以使用JNDI准备的连接数据库的数据源Map,这样就可以访问数据库。我们访问服务器的index.jsp页面,控制台打印我们findAll方法查询的所有用户内容。