|
2 | 2 | The lib of java database ORM simple implementation |
3 | 3 |
|
4 | 4 | --- |
5 | | - |
6 | 5 | #### **Session基本用法** |
7 | 6 | ```java |
8 | 7 | // get session instance by its factory |
@@ -71,18 +70,309 @@ ConfiguratorFactory.setConfigurator(conf); |
71 | 70 | Configurator overrideConf = ConfiguratorFactory.getDefaultInstance(); |
72 | 71 | // 方法4: 读取外部文件实例化配置,配置文件名称可以自由命名 |
73 | 72 | File file = new File("C:\path\filename.properties"); |
74 | | -Configurator extenConf = ConfiguratorFactory.getInstance(file); |
| 73 | +Configurator externalConf = ConfiguratorFactory.getInstance(file); |
75 | 74 | ``` |
76 | 75 |
|
77 | 76 | #### **Session高级用法** |
78 | 77 | ##### **实体类定义** |
| 78 | +目前支持两种类型的实体类: 继承自Entity类,带有JPA注解的POJO类 |
| 79 | + |
| 80 | +openthinks.libs.sql.entity.Entity实例简单对应数据库中的表的一条记录,因此要求该实体类定义时注意以下事项: |
| 81 | + |
| 82 | + 1. 该实体类中的字段或属性名需要与对应表列名一样 |
| 83 | + 2. 该实体类中定义的第一个字段作为对应表的主键 |
| 84 | + 3. 该实体类的名称需与表名相同(仅在调用Session的高级API) |
| 85 | + |
| 86 | +例子: |
| 87 | +``` |
| 88 | +//table structure |
| 89 | +create table message( |
| 90 | + message_id varchar(100), |
| 91 | + message_local varchar(100), |
| 92 | + message_content varchar(1000) |
| 93 | +); |
| 94 | +``` |
| 95 | +```java |
| 96 | +public class Message extends Entity { |
| 97 | + private String message_id; |
| 98 | + private String message_locale; |
| 99 | + private String message_content; |
| 100 | + public String getContent() { |
| 101 | + return message_content; |
| 102 | + } |
| 103 | + public String getLocale() { |
| 104 | + return message_locale; |
| 105 | + } |
| 106 | + public String getId() { |
| 107 | + return message_id; |
| 108 | + } |
| 109 | + public void setId(String messageId) { |
| 110 | + this.message_id = messageId; |
| 111 | + } |
| 112 | + public void setLocale(String locale) { |
| 113 | + this.message_locale = locale; |
| 114 | + } |
| 115 | + public void setContent(String content) { |
| 116 | + this.message_content = content; |
| 117 | + } |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +JPA注解的POJO类没有额外的限制 |
| 122 | +```java |
| 123 | +import javax.persistence.Column; |
| 124 | +import javax.persistence.Entity; |
| 125 | +import javax.persistence.Id; |
| 126 | +import javax.persistence.Table; |
| 127 | +@Entity |
| 128 | +@Table(name = "message") |
| 129 | +public class MessageJPA { |
| 130 | + @Id |
| 131 | + @Column(name = "message_id") |
| 132 | + private String messageId; |
| 133 | + @Column(name = "message_locale") |
| 134 | + private String locale; |
| 135 | + @Column(name = "message_content") |
| 136 | + private String content; |
| 137 | + /* |
| 138 | + *getter/setter method |
| 139 | + */ |
| 140 | +} |
| 141 | +``` |
| 142 | + |
79 | 143 | ##### **增删改** |
| 144 | +在Session的DAO API中分为两大类,一类是无需编写SQL(High level);另一类是需要自行构造SQL(Low level). |
| 145 | + |
| 146 | +```java |
| 147 | +//<T> void openthinks.libs.sql.dhibernate.Session.save(T object) |
| 148 | +// High level |
| 149 | +Session session = SessionFactory.getSession(); |
| 150 | +MessageJPA messageJPA = new MessageJPA(); |
| 151 | +messageJPA.setLocale(Locale.US.toString()); |
| 152 | +messageJPA.setContent("HELLO"); |
| 153 | +messageJPA.setMessageId("2000"); |
| 154 | +session.save(messageJPA); |
| 155 | +Message messageEntity = new Message(); |
| 156 | +messageEntity.setLocale(Locale.CHINA.toString()); |
| 157 | +messageEntity.setContent("你好"); |
| 158 | +messageEntity.setId("3000"); |
| 159 | +session.save(messageEntity); |
| 160 | + |
| 161 | +//int openthinks.libs.sql.dhibernate.Session.add(String sql, String[] params) |
| 162 | +// Low level |
| 163 | +String saveSQL = "INSERT INTO message(message_id,message_locale,message_content) values(?,?,?)"; |
| 164 | +String[] params = {"4000","en_US","Hello again"}; |
| 165 | +int affectRow = session.add(saveSQL,params); |
| 166 | +session.close(); |
| 167 | +``` |
| 168 | + |
| 169 | +```java |
| 170 | +//<T> void openthinks.libs.sql.dhibernate.Session.update(T object) |
| 171 | +Session session = SessionFactory.getSession(); |
| 172 | +MessageJPA message = new MessageJPA(); |
| 173 | +message.setLocale(Locale.CHINA.toString()); |
| 174 | +message.setContent("中国你好"); |
| 175 | +message.setMessageId("2000"); |
| 176 | +session.update(message); |
| 177 | + |
| 178 | +//int openthinks.libs.sql.dhibernate.Session.update(String sql, String[] params) |
| 179 | +String updateSQL = "update message set message_content = ? where message_id =? and message_locale=?"; |
| 180 | +String[] params = {"您好","zh_CN","2000"}; |
| 181 | +session.update(); |
| 182 | +session.close(); |
| 183 | +``` |
| 184 | + |
| 185 | +```java |
| 186 | +//<T> void openthinks.libs.sql.dhibernate.Session.delete(T object) |
| 187 | +MessageJPA messageJPA = new MessageJPA(); |
| 188 | +messageJPA.setLocale(Locale.US.toString()); |
| 189 | +messageJPA.setContent("HELLO"); |
| 190 | +messageJPA.setMessageId("2000"); |
| 191 | +Session session = SessionFactory.getSession(); |
| 192 | +session.delete(messageJPA); |
80 | 193 |
|
81 | | -##### **查询** |
| 194 | +//int openthinks.libs.sql.dhibernate.Session.delete(String sql, String[] params) |
| 195 | +String deleteSQL = "delete message where message_id =? and message_locale=?"; |
| 196 | +String[] params = {"zh_CN","2000"}; |
| 197 | +session.delete(deleteSQL,params); |
| 198 | +session.close(); |
| 199 | +``` |
| 200 | +##### **条件查询** |
| 201 | +对于简单根据单一主键获取记录或获取所有表中记录,推荐使用High level API: |
| 202 | +``` |
| 203 | +// 根据id值获取clz类型的实体对象 |
| 204 | +<T> T openthinks.libs.sql.dhibernate.Session.load(Class<T> clz, Serializable id) |
| 205 | +// 获取所有相应实体类的集合列表 |
| 206 | +<T> List<T> openthinks.libs.sql.dhibernate.Session.list(Class<T> clz) |
| 207 | +``` |
| 208 | +而对于一些复杂的查询,可以使用接下来的方式 |
82 | 209 | ###### **直接SQL语句查询** |
| 210 | +```java |
| 211 | +Session session = SessionFactory.getSession(); |
| 212 | +String querySQL = "SELECT * FROM message WHERE message_id = ? and message_locale= ? "; |
| 213 | +MessgaeJPA messageJPA = session.get(MessageJPA.class, querySQL,new String[]{"2000","zh_CN"}); |
| 214 | +//Messgae message = session.get(Message.class, querySQL,new String[]{"2000","zh_CN"}); |
| 215 | +List<MessageJPA> list = session.list(MessageJPA.class, "SELECT * FROM message",new String[]{}); |
| 216 | +//List<Message> list = session.list(Message.class, "SELECT * FROM message",new String[]{}); |
| 217 | +// 不指定实体类型时,将使用 openthinks.libs.sql.data.Row |
| 218 | +List<Row> rows = session.list("SELECT * FROM message",new String[]{}); |
| 219 | +session.close(); |
| 220 | +``` |
83 | 221 | ###### **简单条件类查询** |
84 | | -###### **智能QueryFilter查询** |
| 222 | +简单条件类: openthinks.libs.sql.lang.Condition是非常底层的,也属于Low level. |
| 223 | +Condition对象可以如下创建: |
| 224 | +``` |
| 225 | +Session session = SessionFactory.getSession(); |
| 226 | +session.createCondition(); // same as Condition.build() |
| 227 | +``` |
| 228 | +``` |
| 229 | +// where 1=1 |
| 230 | +Condition condition1 = Condition.build(); |
| 231 | +// SELECT * FROM message where 1=1 |
| 232 | +Condition condition2 = Condition.build("SELECT * FROM message"); |
| 233 | +// SELECT * FROM message where 1=1 |
| 234 | +Condition condition3 = Condition.build(MessageJPA.class); |
| 235 | +``` |
| 236 | +如何使用:(暂支持 绝对匹配 *=*,模糊匹配 *like*,开始于 *>*,结束于 *<*) |
| 237 | +参考以下 test case: |
| 238 | +```java |
| 239 | +public class ConditionTest { |
| 240 | + private static MessageJPA message = new MessageJPA(); |
| 241 | + private static MessageJPA message2 = new MessageJPA(); |
| 242 | + @BeforeClass |
| 243 | + public static void setUp() { |
| 244 | + Session session = SessionFactory.getSession(); |
| 245 | + message.setMessageId("CONDITION_1"); |
| 246 | + message.setLocale(Locale.US.toString()); |
| 247 | + message.setContent("Condition class regular test"); |
| 248 | + session.save(message); |
85 | 249 |
|
| 250 | + message2.setMessageId("CONDITION_2"); |
| 251 | + message2.setLocale(Locale.US.toString()); |
| 252 | + message2.setContent("Condition class other test"); |
| 253 | + session.save(message2); |
| 254 | + session.close(); |
| 255 | + } |
| 256 | + @Test |
| 257 | + public void regularTest() { |
| 258 | + Session session = SessionFactory.getSession(); |
| 259 | + Condition condition = session.createCondition(); |
| 260 | + condition.setSqlPart("SELECT * FROM message"); |
| 261 | + // 等效于 Condition.build("SELECT * FROM message"); |
| 262 | + |
| 263 | + //第一个参数为条件类型;第二个参数为表字段;第三参数为对应的条件值 |
| 264 | + condition.addItem(Condition.ABSMATCH, "message_id", "CONDITION_1"); |
| 265 | + MessageJPA msg = session.get(MessageJPA.class, condition); |
| 266 | + Assert.assertNotNull(msg); |
| 267 | + Assert.assertEquals(message.getContent(), msg.getContent()); |
| 268 | + session.close(); |
| 269 | + } |
| 270 | + @Test |
| 271 | + public void otherTest() { |
| 272 | + Condition condition = Condition.build(MessageJPA.class) |
| 273 | + .addItem(Condition.LIKEMATCH, "message_id", "CONDITION%") |
| 274 | + .addItem(Condition.ORDER, "message_id", Condition.Order.DESC);//排序 |
| 275 | + Session session = SessionFactory.getSession(); |
| 276 | + List<MessageJPA> list = session.list(MessageJPA.class, condition); |
| 277 | + Assert.assertTrue(list.size() == 2); |
| 278 | + Assert.assertEquals(message2.getMessageId(), list.get(0).getMessageId()); |
| 279 | + session.close(); |
| 280 | + } |
| 281 | + @AfterClass |
| 282 | + public static void tearDown() { |
| 283 | + Session session = SessionFactory.getSession(); |
| 284 | + session.delete(message); |
| 285 | + session.delete(message2); |
| 286 | + session.close(); |
| 287 | + } |
| 288 | +} |
| 289 | +``` |
| 290 | +###### **智能QueryFilter查询** |
| 291 | +```java |
| 292 | +Session session = SessionFactory.getSession(); |
| 293 | +// 获取Query对象 |
| 294 | +Query<MessageJPA> query = session.createQuery(MessageJPA.class); |
| 295 | +// 定义具体的QueryFilter |
| 296 | +QueryFilterGroup group = Filters.group(); |
| 297 | +group.push(Filters.eq("messageId", "4000")); |
| 298 | +group.push(Filters.or()); |
| 299 | +QueryFilterGroup embedGrp = Filters.group(); |
| 300 | +embedGrp.push(Filters.eq("messageId", "2000")); |
| 301 | +embedGrp.push(Filters.eq("locale", "zh_CN")); |
| 302 | +group.push(embedGrp); |
| 303 | +// 最终SQL(MYSQL): |
| 304 | +// select * from `message` where ( `message_id` = '4000' or ( `message_id` = '2000' and message_locale = 'zh_CN') ) |
| 305 | +// 添加到Query对象 |
| 306 | +query.addFilter(group); |
| 307 | +List<MessageJPA> list = query.execute(); |
| 308 | +session.close(); |
| 309 | +``` |
86 | 310 | ##### **简单事务** |
| 311 | +开启事务 `session.beginTransaction();` 另外 `session.beginTransaction(TransactionLevel.TRANSACTION_READ_UNCOMMITTED)` 设置事务级别 |
| 312 | +关闭事务 `session.endTransaction();` 另外 `session.close();` 也会默认关闭事务,如果开启的话. |
| 313 | +例子: |
| 314 | +```java |
| 315 | +public class TransactionTest { |
| 316 | + private static MessageJPA message = new MessageJPA(); |
| 317 | + @BeforeClass |
| 318 | + public static void setUp() { |
| 319 | + Session session = SessionFactory.getSession(); |
| 320 | + message.setMessageId("TRANSACTION"); |
| 321 | + message.setLocale(Locale.US.toString()); |
| 322 | + message.setContent("Transaction test"); |
| 323 | + session.save(message); |
| 324 | + session.close(); |
| 325 | + } |
| 326 | + @Test |
| 327 | + public void beginTransactionTest() throws TransactionException { |
| 328 | + Session session = SessionFactory.getSession(); |
| 329 | + session.beginTransaction(); |
| 330 | + message.setContent("Transaction test rollback"); |
| 331 | + session.update(message); |
| 332 | + int result = session.add("insert into message");//错误语法,新增不成功 |
| 333 | + if (result == 0) { |
| 334 | + session.rollback(); |
| 335 | + } else { |
| 336 | + session.commit(); |
| 337 | + } |
| 338 | + session.endTransaction(); |
| 339 | + |
| 340 | + MessageJPA msg = session.load(MessageJPA.class, message.getMessageId()); |
| 341 | + Assert.assertNotNull(msg); |
| 342 | + Assert.assertEquals("Transaction test", msg.getContent()); |
| 343 | + session.close(); |
| 344 | + } |
| 345 | + @AfterClass |
| 346 | + public static void tearDown() { |
| 347 | + Session session = SessionFactory.getSession(); |
| 348 | + session.delete(message); |
| 349 | + session.close(); |
| 350 | + } |
| 351 | +} |
| 352 | +``` |
87 | 353 |
|
88 | 354 | ##### **连接池** |
| 355 | +目前支持简单的连接池实现 `openthinks.libs.sql.dao.pool.impl.SimpleConnectionPool`; |
| 356 | +可以自行扩展 `openthinks.libs.sql.dao.pool.ConnectionPool`接口,并替换默认的实现: |
| 357 | +```java |
| 358 | +MyConnectionPool connPool = new MyConnectionPool();// your implemented ConnectionPool |
| 359 | +ConnectionPoolManager.setSingletonPoolInstance(connPool);// make it replace the default pool |
| 360 | +``` |
| 361 | +当然使用连接池前,必须配置,在配置文件 dbconfig.properties 中, 加入: |
| 362 | +``` |
| 363 | +USEPOOL=true |
| 364 | +#可选,不配的话默认无限制 |
| 365 | +MAX_ACTIVE=100 |
| 366 | +#可选,不配的话默认无限制 |
| 367 | +MAX_IDLE=10 |
| 368 | +``` |
| 369 | +对于扩展的ConnectionPool, 除了如上所述使用Code替换默认实现, 亦可以在配置文件中指明实现类名称 |
| 370 | +``` |
| 371 | +USEPOOL=true |
| 372 | +POOL_CLASS=openthinks.libs.sql.MyConnectionPool |
| 373 | +``` |
| 374 | +需要注意事项是构造函数的定义: |
| 375 | + |
| 376 | + 1. MyConnectionPool(Configuration) 和 MyConnectionPool() 至少需要定义一个 |
| 377 | + 2. MyConnectionPool() 需要自行获取配置类,以确保获取到数据库连接 |
| 378 | + 3. 优先使用 MyConnectionPool(Configuration) 构造函数 |
0 commit comments