AIOps 一场颠覆传统运维的盛筵
1021
2022-10-25
达梦DM7使用mybatis示例
DM7是达梦公司出品的商业数据库,与Oracle高度兼容,是一款大型通用关系型数据库。
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
本系列文章向大家介绍如何在DM7上运行MyBatis。
一、环境准备
1、数据库
利用SYSDBA登录,创建一个新用户test,sql脚本如下:
--请以SYSDBA登录执行以下脚本 -- 创建test用户,用户密码Test12345, 默认表空间为ts_test -- 创建表空间 CREATETABLESPACE ts_test DATAFILE'test.DBF'SIZE 128; -- 创建用户 CREATEUSER test IDENTIFIEDBY "Test12345" DEFAULTTABLESPACE ts_test; -- 为方便test用户后续操作,直接授予DBA角色权限,生产环境慎用 GRANT DBA TO test; |
2、Java工程
创建maven工程目录结构如下
mybatis\ 项目根目录 src\main\java 存放java源文件 src\main\resources 存放各种配置文件 lib\ 存放本地Jar包 pom.xml maven项目文件 |
注意,从dm7安装目录\drivers\jdbc目录下,将Dm7JdbcDriver16.jar文件复制到lib目录下,系统运行需要用到。
pom文件中,添加三个依赖项如下:
<dependencies> <dependency> <groupId>com.dameng</groupId> <artifactId>Dm7JdbcDriver16</artifactId> <version>7.6.0.115</version> <scope>system</scope> <systemPath> ${basedir}/lib/Dm7JdbcDriver16.jar </systemPath> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> |
其中Dm7JdbcDriver16的scope为system,并且配置systemPath指向lib目录下的Dm7JdbcDriver16.jar文件,这样maven就不会从maven中央仓库查找文件,而是使用本地jar包。
二、CRUD操作
1、创建示例表
以test用户登录,执行以下脚本
--以test用户重新登录后,再执行下列脚本 -- 用户信息表 CREATETABLE t_user ( id INTNOTNULL,--用户标识 name VARCHAR(20)NOTNULL,--姓名 phone VARCHAR(50),-- 手机 email VARCHAR(50),-- 邮箱 PRIMARYKEY(id) ); |
2、建立对应的pojo对象
package org.dmstudy.mybatis.domain; publicclass User { private Integer id; private String name; private String phone; private String email; //getter/setter省略 } |
对象属性名与表字段名保持一致,这样方便mybatis自动映射,简化后续代码。
3、配置文件
建立resources\mybatis-config.xml,内容如下
<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEconfiguration PUBLIC"-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 读取加载配置文件信息 --> <propertiesresource="jdbc.properties"/> <settings> <settingname="logImpl"value="LOG4J"/> </settings> <!-- 别名 --> <typeAliases> <typeAliastype="org.dmstudy.mybatis.domain.User"alias="User"/> </typeAliases> <!-- 配置环境变量,可以配置多个,有默认值 --> <environmentsdefault="dev"> <environmentid="dev"> <transactionManagertype="JDBC"/> <dataSourcetype="POOLED"> <propertyname="driver"value="${jdbc.driver}"/> <propertyname="url"value="${jdbc.url}"/> <propertyname="username"value="${jdbc.username}"/> <propertyname="password"value="${jdbc.password}"/> </dataSource> </environment> </environments> <!-- 配置映射文件 --> <mappers> <mapperresource="org/dmstudy/mybatis/crud/dao/UserMapper.xml"/> </mappers> </configuration> |
typeAliases节定义了一个别名User,方便在后续配置参数类型、返回值类型时使用。
使用缺省的dev环境配置,其中transactionManager使用JDBC类型,dataSource使用POOLED方式,数据库连接参数使用外部属性文件内容配置。
在resources目录下创建jdbc.properties文件,通过配置文件中的
jdbc.driver=dm.jdbc.driver.DmDriver jdbc.url=jdbc:dm://localhost:5236 jdbc.username=test jdbc.password=Test12345 |
注意:jdbc.url配置中,最后面只有ip地址和端口,不需要添加数据库名、实例名。这里jdbc.username必须使用前面创建表的用户test,不能使用SYSDBA或其他用户,否则会导致找不到表之类的sql错误。
设置
# Global logging configuration log4j.rootLogger=DEBUG,stdout # 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 |
定义了向标准控制台输出DEBUG级别的日志,可以查看mybatis生成sql语句和执行情况。
4、XML映射文件
MyBatis利用Xml映射文件,实现sql语句和Mapper接口方法的映射。在mybati-config.xml文件中,我们配置了一个mapper,对应的resource文件为classpath路径下的org/dmstudy/mybatis/crud/dao/UserMapper.xml文件,其内容如下:
<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEmapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mappernamespace="org.dmstudy.mybatis.crud.dao.UserMapper"> <insertid="insert"parameterType="User"> insert into t_user (id,name,phone,email) values (#{id},#{name}, #{phone}, #{email}) </insert> <selectid="retrieve"parameterType="int"resultType="User"> select id,name,phone,email from t_user where id = #{id} </select> <updateid="update"parameterType="User"> update t_user set name=#{name},phone=#{phone},email=#{email} where id=#{id} </update> <deleteid="delete"parameterType="int"> delete from t_user where id = #{id} </delete> <selectid="listAll"resultType="User"> select id,name,phone,email from t_user </select> </mapper> |
在这个xml映射文件中,根节点mapper元素有一个重要属性namespace,按照mybatis文档的建议,该标识应和xml映射文件在classpath下的路径对应保持一致(将文件路径中的”/”替换为”.”,去掉最后的后缀名就得到这个标识)。按这个规则,此处namespace的值设置为"org.dmstudy.mybatis.crud.dao.UserMapper"。
在mapper节点下,我们还定义了insert,update,delete,select等几种节点,它们分别对应了sql操作中相应的INSERT、UPDATE、DELETE、SELECT四种类型语句,节点的内容是用来生成sql语句的模板。
以Insert节点为例,id=”insert” 这个属性用于配置该语句的唯一标识,在对应的namespace中该标识不要重名,采用有意义的命名方法便于理解和记忆。同时由于该id在后面使用中还会对应java接口的方法名,所以命名最好还要符合java方法的命名习惯。
parameterType=“User“ 这个属性配置了执行该语句时提供的参数类型,这里”User”就是在mybatis-config.xml文件中typeAliases中定义的,以简洁的别名表示参数是一个User对象。如果不使用User别名,也可直接指定类全名”org.dmstudy.mybatis.domain.User”。
sql模板中values部分使用了 #{id}、#{name}等格式。在mybatis中,该部分在生成sql语句时会替换为?,并且该语句会采用PreparedStatement来编译执行,相应的参数值则使用输入参数(User对象)的相应属性来设置。
Select节点中,resultType="User",表示该语句执行后,mybatis会把底层jdbc执行select语句返回的ResultSet中每一行记录都转化为一个User对象。
5、Mapper接口
创建org.dmstudy.mybatis.crud.dao UserMapper.java文件,内容如下:
package org.dmstudy.mybatis.crud.dao; import java.util.List; import org.dmstudy.mybatis.domain.User; publicinterface UserMapper { intinsert(User user); User retrieve(intid); int update(User user); int delete(intid); List<User> listAll(); } |
按照mybatis的惯例,该接口的全名org.dmstudy.mybatis.crud.dao.UserMapper跟UserMapper.xml中定义的namespace保持一致,接口中的每个方法与UserMapper.xml中定义的映射语句保持一致。以retrieve方法为例,方法名对应映射语句的id,方法参数int类型与映射语句parameterType一致,方法返回值类型与映射语句的resultType一致。
INSERT、UPDATE、DELETE类型的sql语句执行后jdbc会返回记录影响行数,对应的java方法返回值如果设为int则可以获取到这个值,用以判断sql语句是否按预期正确执行。
SELECT类型的sql语句执行后jdbc返回的是一个结果集,对于基于主键的查询,能明确返回最多一条记录时,java方法返回值可直接设为java对象(如User);对于基于一般条件查询结果记录数不确定的情况, java方法返回值一般可设置为List类型。
6、调用代码
Mybatis对象初始化
参见CrudApp的init方法,首先通过classpath下的mybatis-config.xml文件资源,利用SqlSessionFactoryBuilder来build出一个SqlSessionFactory对象,后续可以通过这个sqlSessionFactory对象,随时按需打开一个SqlSession对象。而SqlSession则是用来执行sql语句、提交事务等操作的主要对象。
package org.dmstudy.mybatis.crud; …… publicclass CrudApp { SqlSessionFactory sqlSessionFactory; publicvoid init() throws IOException { InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); if (sqlSessionFactory == null) { sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } } } |
执行sql操作
在定义xml映射文件和相应的java接口之后,用户无需实现这些接口,可利用sqlSession对象获取这个接口,当某个接口方法被调用时,mybatis会自动将其转换为xml映射文件中定义的sql语句执行。
以insert方法为例,代码如下:
publicvoid insert() { System.out.println("---insert ---"); // 新建user对象 User user = new User(); user.setId(1); user.setName("dmtech"); user.setPhone("400-6489899"); user.setEmail("dmtech@dameng.com"); SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 将user插入数据库 intcnt = mapper.insert(user); sqlSession.commit(); System.out.println("成功插入 " + cnt + "条记录! "); } catch (Exception e) { System.err.println("insert执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); sqlSession.rollback(); } finally { sqlSession.close(); } } |
执行时,从log4j输出日志,可查看执行过程详细信息
---insert --- DEBUG [main] - Opening JDBC Connection DEBUG [main] - Created connection 203849460. DEBUG [main] - Setting autocommit to false on JDBC Connection [dm.jdbc.driver.DmdbConnection@c267ef4] DEBUG [main] - ==> Preparing: insert into t_user (id,name,phone,email) values (?,?, ?, ?) DEBUG [main] - ==> Parameters: 1(Integer), dmtech(String), 400-6489899(String), dmtech@dameng.com(String) DEBUG [main] - <== Updates: 1 DEBUG [main] - Committing JDBC Connection [dm.jdbc.driver.DmdbConnection@c267ef4] 成功插入 1条记录! DEBUG [main] - Resetting autocommit to true on JDBC Connection [dm.jdbc.driver.DmdbConnection@c267ef4] DEBUG [main] - Closing JDBC Connection [dm.jdbc.driver.DmdbConnection@c267ef4] DEBUG [main] - Returned connection 203849460 to pool. |
首先当open一个新的SqlSession时,mybatis会从连接池中获取一个Connection,注意缺省配置下,该连接池autocommit被设置为false,因此在执行insert语句之后,要记得调用sqlSession.commit,否则数据不会保持到数据库中。
当通过sqlSession获取UserMapper接口,并执行insert(user)方法时,mybatis会根据对应xml映射文件生成PrepareStatement,语句为:insert into t_user (id,name,phone,email) values (?,?, ?, ?),并利用输入user对象的属性,设置参数值。
最后该语句执行后,日志输出Updates: 1,表明该操作影响了记录行数为1,即语句执行成功,插入了1条记录。
为保证事务完整性,以及资源的正确释放,获取sqlSession之后,应该使用try…catch…finally语句块执行,当catch到异常时要记得rollback,在finally中注意close,释放sqlSession资源,对应日志中也可看出,close实际上是将Connection返回到连接池中。
7、完整代码
完成的project工程目录及文件结构如下:
完整的CrudApp.java代码如下
package org.dmstudy.mybatis.crud; import java.io.IOException; import java.io.InputStream; import java.util.List; 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 org.dmstudy.mybatis.crud.dao.UserMapper; import org.dmstudy.mybatis.domain.User; publicclass CrudApp { SqlSessionFactory sqlSessionFactory; publicvoid init() throws IOException { InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); if (sqlSessionFactory == null) { sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } } publicvoid insert() { System.out.println("---insert ---"); // 新建user对象 User user = new User(); user.setId(1); user.setName("dmtech"); user.setPhone("400-6489899"); user.setEmail("dmtech@dameng.com"); SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 将user插入数据库 intcnt = mapper.insert(user); sqlSession.commit(); System.out.println("成功插入 " + cnt + "条记录! "); } catch (Exception e) { System.err.println("insert执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); sqlSession.rollback(); } finally { sqlSession.close(); } } publicvoid retrieve() { System.out.println("---retrieve ---"); intid = 1; SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 查询user User user = mapper.retrieve(id); if (user == null) { System.out.println("id=" + id + "的记录不存在! "); } else { System.out.println("成功获取User对象 。User[id= " + user.getId() + ", name= " + user.getName() + "]"); } } catch (Exception e) { System.err.println("retrieve执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); } finally { sqlSession.close(); } } publicvoid update() { System.out.println("---update ---"); intid = 1; SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 查询user User user = mapper.retrieve(id); if (user == null) { System.out.println("id=" + id + "的记录不存在! "); return; } // 修改user.name String name = user.getName(); if ("dmtech".equals(name)) { user.setName("DMTECH"); } else { user.setName("dmtech"); } intcnt = mapper.update(user); sqlSession.commit(); System.out.println("成功修改了 " + cnt + "条记录! "); } catch (Exception e) { System.err.println("update执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); sqlSession.rollback(); } finally { sqlSession.close(); } } publicvoid delete() { System.out.println("---delete ---"); intid = 1; SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 查询user intcnt = mapper.delete(id); sqlSession.commit(); System.out.println("成功删除了" + cnt + "条记录! "); } catch (Exception e) { System.err.println("delete执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); sqlSession.rollback(); } finally { sqlSession.close(); } } publicvoid listAll() { System.out.println("--- listAll ---"); SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 查询user列表 List<User> user_list = mapper.listAll(); System.out.println("查询到" + user_list.size() + "条记录! "); for (User user : user_list) { System.out.println("User[id= " + user.getId() + ", name= " + user.getName() + "]"); } } catch (Exception e) { System.err.println("listAll执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); } finally { sqlSession.close(); } } publicstaticvoid main(String[] args) throws Exception { CrudApp app = new CrudApp(); app.init(); // insert app.insert(); // retrieve app.retrieve(); // update app.update(); // list app.listAll(); // delete app.delete(); } } |
发表评论
暂时没有评论,来抢沙发吧~